如何使用 Cocoapods 调整 Kotlin Multiplatform 项目的 Swift 类名?

Posted

技术标签:

【中文标题】如何使用 Cocoapods 调整 Kotlin Multiplatform 项目的 Swift 类名?【英文标题】:How to adjust Swift classnames for Kotlin Multiplatform project with Cocoapods? 【发布时间】:2019-11-27 18:59:36 【问题描述】:

在我的 Kotlin 多平台项目中,我大量使用命名空间。另外,由于我使用的是 MVP,所以我有相似的类名。例如:

com.company.project.usecase1.Model
com.company.project.usecase1.View
com.company.project.usecase1.Presenter
com.company.project.usecase2.Model
com.company.project.usecase2.View
com.company.project.usecase2.Presenter

现在我想在 ios 应用程序中使用它(用 Swift 编写)。 所以我已将 iOS 目标添加到 build.gradle - 就像 example 中的所有内容。我能够生成 Cocoapod (gradlew podspec) 并使用它 Swift 应用程序。

build.gradle的相关部分:

version = "$rootProject.module_version"

kotlin 
    cocoapods 
        summary = "App MVP of NotesClientApp"
        homepage = "some url"
    

但是由于 Swift 没有命名空间并且类名看起来很相似,所以生成的 obj-c 包装器看起来很丑:它在类名中使用人工突变(下划线)来区分名称,例如。

__attribute__((swift_name("Presenter__")))
@protocol App_mvpPresenter__ <App_mvpBasePresenter>
@required
@end;

__attribute__((swift_name("View__")))
@protocol App_mvpView__ <App_mvpBaseView>
@required
- (void)showValidationErrorError:(App_mvpKotlinException *)error __attribute__((swift_name("showValidationError(error:)")));
- (void)showNotesList __attribute__((swift_name("showNotesList()")));
@property NSString *host __attribute__((swift_name("host")));
@property NSString *port __attribute__((swift_name("port")));
@end;

__attribute__((swift_name("Model__")))
@interface App_mvpModel__ : KotlinBase
- (instancetype)initWith_host:(NSString * _Nullable)_host _port:(App_mvpUInt * _Nullable)_port __attribute__((swift_name("init(_host:_port:)"))) __attribute__((objc_designated_initializer));
- (void)updateHost:(NSString *)host port:(uint32_t)port __attribute__((swift_name("update(host:port:)")));
@property (readonly) NSString * _Nullable host __attribute__((swift_name("host")));
@property (readonly) App_mvpUInt * _Nullable port __attribute__((swift_name("port")));
@property id<App_mvpPresenter__> _Nullable presenter __attribute__((swift_name("presenter")));
@end;

__attribute__((objc_subclassing_restricted))
__attribute__((swift_name("PresenterImpl__")))
@interface App_mvpPresenterImpl__ : KotlinBase <App_mvpPresenter__>
- (instancetype)initWithModel:(App_mvpModel__ *)model __attribute__((swift_name("init(model:)"))) __attribute__((objc_designated_initializer));
- (void)attachViewView:(id<App_mvpView__>)view __attribute__((swift_name("attachView(view:)")));
- (void)onModelChanged __attribute__((swift_name("onModelChanged()")));
- (void)onViewChanged __attribute__((swift_name("onViewChanged()")));
- (void)onViewDetached __attribute__((swift_name("onViewDetached()")));
@property (readonly) App_mvpModel__ *model __attribute__((swift_name("model")));
@end;

我想应该有一些调整行为的可能性:添加一些配置文件或注释以进行命名调整。

在 Obj-c/Swift 中重命名与 Kotlin 无关的类的任何其他可能性?我尝试使用 Swift 类型别名,但只收到“类型别名无效重新声明”错误。

有什么想法吗?

PS。我也可以看到模块名称(app-mvp)作为前缀,例如。类名App_mvpView__ - 是否有可能在不更改 Gradle 模块名称的情况下调整生成的框架名称(因为我仍然想使用正确的 JVM 构建工件名称:app-mvp-jvm.jar)?

PPS。我确实理解重命名类以使它们在所有命名空间中唯一会更容易,但无论如何。

【问题讨论】:

您是如何解决重复命名问题的? 【参考方案1】:

目前无法覆盖原生的类名。 javascript MPP 有一个名为JSName 的注解,所以我以后不会排除它。要更改您的框架名称,您只需在目标下的framework 配置中设置baseName 值。

    fromPreset(iOSTarget, 'ios') 
        binaries 
            framework 
                baseName = "MyFrameworkName"
            
        
    

如果您正在使用packForXcode 任务,您可能需要更新它以找到您的新框架。我的看起来像这样:

task packForXCode(type: Sync) 
    final File frameworkDir = new File(buildDir, "xcode-frameworks")
    final String mode = (project.findProperty("XCODE_CONFIGURATION")?.toUpperCase() ?: 'DEBUG').split("_").first()


    inputs.property "mode", mode
    def bin = kotlin.targets.ios.compilations.main.target.binaries.findFramework("", mode)
    dependsOn bin.linkTask

    from bin.outputDirectory
    into frameworkDir

    doLast 
        new File(frameworkDir, 'gradlew').with 
            text = "#!/bin/bash\nexport 'JAVA_HOME=$System.getProperty("java.home")'\ncd '$rootProject.rootDir'\n./gradlew \$@\n"
            setExecutable(true)
        
    

Mine 还具有自定义功能以支持 Xcode 中的多个项目方案。应用程序可以指向的每个环境(开发、测试、产品)都有一个。

【讨论】:

它适用于 CocoaPods(不是框架方法)吗? BTW 现在建议的目标语法看起来有点不同:iosArm32() (../iosArm64/iosX64) 而不是 fromPreset(iOSTarget, 'ios'),但感谢您的指点。 我已经检查过了 - 它不起作用:拥有 cocoapods 插件会伤害 - 目标是由它创建的,我可以更改框架(调试 + 发布)baseNames(使用targets.iosX64.binaries .findAll it instanceof org.jetbrains.kotlin.gradle.plugin.mpp.Framework .every it.baseName = "AppMvp" ),但不适用于可可足类。在 podspec 文件中 spec.name 仍然是 app_mvp 大概可以这样:github.com/JetBrains/kotlin-native/issues/…

以上是关于如何使用 Cocoapods 调整 Kotlin Multiplatform 项目的 Swift 类名?的主要内容,如果未能解决你的问题,请参考以下文章

Kotlin 多平台项目依赖于另一个带有 cocoapods 的项目

Google 登录 CocoaPods 已弃用

Kotlin Multiplatform 项目包含 cocoapod 依赖项

Kotlin:将函数传递给类

在 Kotlin 中调整对话框片段的大小

CocoaPods安装和使用教程