如何将 Mapbox iOS 框架集成到 Kotlin 原生中
How to integrate Mapbox iOS framework into Kotlin native
我正在尝试将 Mapbox 的框架集成到我的 Kotlin 多平台库中。但是我遇到了 cinterop 部分的编译错误。
第一个问题是 MapboxMobileEvents 框架的编译步骤。 MapboxMobileEvents.h
包含引用不存在的 MapboxMobileEvents
目录的导入语句。我创建了一个符号 link 来解决这个问题。
之后我从 clang 中收到错误消息。
Exception in thread "main" java.lang.IllegalStateException: clang_parseTranslationUnit2 failed with CXError_ASTReadError;
sourceFile = /var/folders/vj/mvxq9qtn1r9_8x2c7zyx04_m0000gn/T/tmp6661284981682757951tmp8536987580934998728.m
arguments = -fmodules -isystem /Users/mkrussel/.konan/dependencies/clang-llvm-apple-8.0.0-darwin-macos/lib/clang/8.0.0/include -B/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin -fno-stack-protector -stdlib=libc++ -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator13.5.sdk -miphoneos-version-min=9.0 -O2 -I/Users/mkrussel/pangea/mapbox-native/pangea-mapbox/frameworks/MapboxMobileEvents.framework/Headers -fobjc-arc -include-pch /var/folders/vj/mvxq9qtn1r9_8x2c7zyx04_m0000gn/T/tmp1085765932502683439.pch -Werror=implicit-function-declaration -ferror-limit=0
tmp6661284981682757951tmp8536987580934998728.m
名称在每次构建时都会更改,但文件始终为空,我认为这是导致问题的原因。
我不明白是什么导致文件为空。
我是不是配置错了cinterop?
是不是 Kotlin 插件坏了?
Mapbox 框架是否与 Kotlin 原生不兼容?
我的 gradle 文件看起来像
iOSTarget("ios") {
compilations {
@Suppress("UNUSED_VARIABLE")
val main by getting {
kotlinOptions.freeCompilerArgs = listOf("-Xobjc-generics")
val frameworksDir = "$projectDir/frameworks"
cinterops(Action {
val mapboxEvents by creating {
defFile("$frameworksDir/mapbox-events.def")
includeDirs.allHeaders("$frameworksDir/MapboxMobileEvents.framework/Headers")
}
})
cinterops(Action {
val mapbox by creating {
defFile("$frameworksDir/mapbox.def")
includeDirs.allHeaders("$frameworksDir/Mapbox.framework/Headers")
}
})
}
}
}
mapbox-events.def
package = framework.mapbox.events
language = Objective-C
headers = MapboxMobileEvents.h
headersFilter = **
compilerOpts = -F/Users/mkrussel/pangea/mapbox-native/pangea-mapbox/frameworks -framework MapboxMobileEvents -fmodules
linkerOpts = -F/Users/mkrussel/pangea/mapbox-native/pangea-mapbox/frameworks -framework MapboxMobileEvents
mapbox.def
package = framework.mapbox
language = Objective-C
headers = Mapbox.h
headersFilter = **
compilerOpts = -F/Users/mkrussel/pangea/mapbox-native/pangea-mapbox/frameworks -framework Mapbox -fmodules
linkerOpts = -F/Users/mkrussel/pangea/mapbox-native/pangea-mapbox/frameworks -framework Mapbox
在 .def
文件中使用完整路径名以确保没有相对路径问题。
尝试仅使用 mapbox.def
或 mapbox-events.def
文件之一仍然会产生相同的错误。
使用:
- Kotlin 版本 1.3.72
- Xcode 版本 11.5 (11E608c)
我也试过了,同样失败。
iOSTarget("ios") {
val frameworksDir = "$projectDir/frameworks"
compilations {
@Suppress("UNUSED_VARIABLE")
val main by getting {
kotlinOptions.freeCompilerArgs = listOf("-Xobjc-generics")
cinterops(Action {
val mapboxEvents by creating {
defFile("$frameworksDir/mapbox-events.def")
packageName("com.mapbox.events")
header("$frameworksDir/MapboxMobileEvents.framework/Headers/MapboxMobileEvents.h")
compilerOpts("-fmodules")
includeDirs.allHeaders("$frameworksDir/MapboxMobileEvents.framework/Headers")
}
})
cinterops(Action {
val mapbox by creating {
defFile("$frameworksDir/mapbox.def")
packageName("com.mapbox")
header("$frameworksDir/Mapbox.framework/Headers/Mapbox.h")
compilerOpts("-fmodules")
includeDirs.allHeaders("$frameworksDir/Mapbox.framework/Headers")
}
})
}
}
binaries {
executable {
linkerOpts = mutableListOf("-F$frameworksDir", "-framework", "Mapbox", "-framework", "MapboxMobileEvents")
}
}
}
mapbox-event.def
language = Objective-C
mapbox.def
language = Objective-C
我已经使用了一些框架,下面是我发现的内容。
您不需要 .def
文件中的那些 compilerOpts
。这个选项是针对 cinterop 工具的,不是最终的二进制编译。您在此处设置的选项可能应该转到 Gradle 脚本的 kotlin.binaries.framework
块。可以在 documentation.
中找到更多信息
UPD:这个建议并不完全正确,因为它只为 Mapbox 框架修复了绑定的生成。问题是 cinterop
工具在 -fmodules
编译器标志方面存在问题。此标志对于 MapboxMobileEvents 框架很重要,因为它在使用 Foundation 和 CoreFoundation 框架时依赖于 @import
语法。
请订阅 YouTrack 问题 here。当它被修复时,我会在这里进行更新。
我最终成功了。
mapbox.def
language = Objective-C
modules = Mapbox
linkerOpts = -framework Mapbox
在build.gradle.kts
kotlin {
ios {
val frameworkLocation = File(rootDir, "native/TestApp/Pods/Mapbox-iOS-SDK/dynamic/").absolutePath
val frameworks = "-F$frameworkLocation"
compilations {
@Suppress("UNUSED_VARIABLE")
val main by getting {
cinterops {
val mapbox by creating {
defFile = File("$projectDir/libs/mapbox.def")
packageName("com.mapbox")
compilerOpts(frameworks)
}
}
}
}
binaries.matching { it is org.jetbrains.kotlin.gradle.plugin.mpp.Framework }
.configureEach {
val framework = this as org.jetbrains.kotlin.gradle.plugin.mpp.Framework
framework.linkerOpts(frameworks)
}
}
}
似乎我遗漏的一大块是模块行
我正在尝试将 Mapbox 的框架集成到我的 Kotlin 多平台库中。但是我遇到了 cinterop 部分的编译错误。
第一个问题是 MapboxMobileEvents 框架的编译步骤。 MapboxMobileEvents.h
包含引用不存在的 MapboxMobileEvents
目录的导入语句。我创建了一个符号 link 来解决这个问题。
之后我从 clang 中收到错误消息。
Exception in thread "main" java.lang.IllegalStateException: clang_parseTranslationUnit2 failed with CXError_ASTReadError;
sourceFile = /var/folders/vj/mvxq9qtn1r9_8x2c7zyx04_m0000gn/T/tmp6661284981682757951tmp8536987580934998728.m
arguments = -fmodules -isystem /Users/mkrussel/.konan/dependencies/clang-llvm-apple-8.0.0-darwin-macos/lib/clang/8.0.0/include -B/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin -fno-stack-protector -stdlib=libc++ -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator13.5.sdk -miphoneos-version-min=9.0 -O2 -I/Users/mkrussel/pangea/mapbox-native/pangea-mapbox/frameworks/MapboxMobileEvents.framework/Headers -fobjc-arc -include-pch /var/folders/vj/mvxq9qtn1r9_8x2c7zyx04_m0000gn/T/tmp1085765932502683439.pch -Werror=implicit-function-declaration -ferror-limit=0
tmp6661284981682757951tmp8536987580934998728.m
名称在每次构建时都会更改,但文件始终为空,我认为这是导致问题的原因。
我不明白是什么导致文件为空。
我是不是配置错了cinterop?
是不是 Kotlin 插件坏了?
Mapbox 框架是否与 Kotlin 原生不兼容?
我的 gradle 文件看起来像
iOSTarget("ios") {
compilations {
@Suppress("UNUSED_VARIABLE")
val main by getting {
kotlinOptions.freeCompilerArgs = listOf("-Xobjc-generics")
val frameworksDir = "$projectDir/frameworks"
cinterops(Action {
val mapboxEvents by creating {
defFile("$frameworksDir/mapbox-events.def")
includeDirs.allHeaders("$frameworksDir/MapboxMobileEvents.framework/Headers")
}
})
cinterops(Action {
val mapbox by creating {
defFile("$frameworksDir/mapbox.def")
includeDirs.allHeaders("$frameworksDir/Mapbox.framework/Headers")
}
})
}
}
}
mapbox-events.def
package = framework.mapbox.events
language = Objective-C
headers = MapboxMobileEvents.h
headersFilter = **
compilerOpts = -F/Users/mkrussel/pangea/mapbox-native/pangea-mapbox/frameworks -framework MapboxMobileEvents -fmodules
linkerOpts = -F/Users/mkrussel/pangea/mapbox-native/pangea-mapbox/frameworks -framework MapboxMobileEvents
mapbox.def
package = framework.mapbox
language = Objective-C
headers = Mapbox.h
headersFilter = **
compilerOpts = -F/Users/mkrussel/pangea/mapbox-native/pangea-mapbox/frameworks -framework Mapbox -fmodules
linkerOpts = -F/Users/mkrussel/pangea/mapbox-native/pangea-mapbox/frameworks -framework Mapbox
在 .def
文件中使用完整路径名以确保没有相对路径问题。
尝试仅使用 mapbox.def
或 mapbox-events.def
文件之一仍然会产生相同的错误。
使用:
- Kotlin 版本 1.3.72
- Xcode 版本 11.5 (11E608c)
我也试过了,同样失败。
iOSTarget("ios") {
val frameworksDir = "$projectDir/frameworks"
compilations {
@Suppress("UNUSED_VARIABLE")
val main by getting {
kotlinOptions.freeCompilerArgs = listOf("-Xobjc-generics")
cinterops(Action {
val mapboxEvents by creating {
defFile("$frameworksDir/mapbox-events.def")
packageName("com.mapbox.events")
header("$frameworksDir/MapboxMobileEvents.framework/Headers/MapboxMobileEvents.h")
compilerOpts("-fmodules")
includeDirs.allHeaders("$frameworksDir/MapboxMobileEvents.framework/Headers")
}
})
cinterops(Action {
val mapbox by creating {
defFile("$frameworksDir/mapbox.def")
packageName("com.mapbox")
header("$frameworksDir/Mapbox.framework/Headers/Mapbox.h")
compilerOpts("-fmodules")
includeDirs.allHeaders("$frameworksDir/Mapbox.framework/Headers")
}
})
}
}
binaries {
executable {
linkerOpts = mutableListOf("-F$frameworksDir", "-framework", "Mapbox", "-framework", "MapboxMobileEvents")
}
}
}
mapbox-event.def
language = Objective-C
mapbox.def
language = Objective-C
我已经使用了一些框架,下面是我发现的内容。
您不需要 .def
文件中的那些 compilerOpts
。这个选项是针对 cinterop 工具的,不是最终的二进制编译。您在此处设置的选项可能应该转到 Gradle 脚本的 kotlin.binaries.framework
块。可以在 documentation.
UPD:这个建议并不完全正确,因为它只为 Mapbox 框架修复了绑定的生成。问题是 cinterop
工具在 -fmodules
编译器标志方面存在问题。此标志对于 MapboxMobileEvents 框架很重要,因为它在使用 Foundation 和 CoreFoundation 框架时依赖于 @import
语法。
请订阅 YouTrack 问题 here。当它被修复时,我会在这里进行更新。
我最终成功了。
mapbox.def
language = Objective-C
modules = Mapbox
linkerOpts = -framework Mapbox
在build.gradle.kts
kotlin {
ios {
val frameworkLocation = File(rootDir, "native/TestApp/Pods/Mapbox-iOS-SDK/dynamic/").absolutePath
val frameworks = "-F$frameworkLocation"
compilations {
@Suppress("UNUSED_VARIABLE")
val main by getting {
cinterops {
val mapbox by creating {
defFile = File("$projectDir/libs/mapbox.def")
packageName("com.mapbox")
compilerOpts(frameworks)
}
}
}
}
binaries.matching { it is org.jetbrains.kotlin.gradle.plugin.mpp.Framework }
.configureEach {
val framework = this as org.jetbrains.kotlin.gradle.plugin.mpp.Framework
framework.linkerOpts(frameworks)
}
}
}
似乎我遗漏的一大块是模块行