Compose Multiplatform macOS应用调用原生函数的实现、签名及打包问题咨询
Compose Multiplatform macOS应用调用原生函数的实现、签名及打包问题咨询
我用Compose Multiplatform开发了一个macOS应用,需要调用几个原生系统函数,比如访问文件夹进行写入操作,或者获取设备主机名。
我了解到可以通过JNI创建dylib库,然后从Kotlin调用所需方法。以下是我目前的实现:
MacOsUtils.swift
@objc public class MacOsUtils: NSObject { @objc public func getDeviceHostName() -> String { if let hostName = Host.current().localizedName { print("Device host name: \(hostName)") return hostName } else { print("Unable to retrieve device host name") return "Unknown Device" } } }
MacOsUtilsWrapper.mm
#include <jni.h> #include <string> #include "MacOsUtils-Swift.h" #include <Foundation/Foundation.h> JavaVM* jvm = nullptr; extern "C" { JNIEXPORT jstring JNICALL Java_com_my_app_common_core_persits_MacOsUtils_getDeviceHostName(JNIEnv* env, jobject obj) { @autoreleasepool { MacOsUtils* macOsUtils = [MacOsUtils createInstance]; if (!macOsUtils) { NSLog(@"Failed to create MacOsUtils instance"); return nullptr; } NSString* deviceName = [macOsUtils getDeviceHostName]; if (deviceName != nil) { const char* deviceNameCStr = [deviceName UTF8String]; return env->NewStringUTF(deviceNameCStr); } else { return nullptr; } } } }
编译与签名命令
我用以下命令编译库:
swiftc -emit-library -emit-objc-header -emit-objc-header-path MacOsUtils-Swift.h -static -o libMacOsUtils.a MacOsUtils.swift clang++ -I"$JAVA_HOME/include" -I"$JAVA_HOME/include/darwin" -I"." -shared -o libMacOsUtilsWrapper.dylib MacOsUtilsWrapper.mm -L. -lMacOsUtils -framework Foundation -Wl,-all_load
然后用这个命令签名库:
codesign --force --sign "3rd Party Mac Developer Application: My Name (TEAM ID)" --timestamp --options runtime libMacOsUtilsWrapper.dylib
Kotlin加载代码
我把libMacOsUtilsWrapper.dylib文件放在common/src/desktopMain/resources文件夹里,然后在Kotlin代码中把库复制到临时目录并尝试加载:
object MacOsUtils { init { loadLibrary() } private fun loadLibrary() { System.setProperty("jna.nosys", "true") val libName = "libMacOsUtilsWrapper.dylib" checkNotNull(this::class.java.classLoader?.getResource(libName)) { "Library $libName not found in resources" } val tmpDir = Files.createTempDirectory("MyApp").toFile() Napier.d("Loading $libName to $tmpDir") val tmpLib = File(tmpDir, libName) if (!tmpLib.exists()) { this::class.java.classLoader?.getResourceAsStream(libName)?.use { inputStream -> FileOutputStream(tmpLib).use { outputStream -> inputStream.copyTo(outputStream) } } } @Suppress("UnsafeDynamicallyLoadedCode") System.load(tmpLib.absolutePath) } external fun getDeviceHostName(): String? }
遇到的问题
在本地Android Studio中运行应用时一切正常,但发布到TestFlight后就出问题了。启动应用时会遇到这个错误:
The file "libMacOsUtilsWrapper.dylib" couldn’t be opened because Apple cannot check it for malicious software.
我的疑问
我有三个问题想请教:
- 这是在Compose Multiplatform macOS应用中调用原生函数的正确方式吗?
- 应该如何正确签名
dylib文件?我现在用的是3rd Party Mac Developer Application身份,这个方式对吗? - 应该如何打包
dylib文件,才能让它在Android Studio运行时和发布到TestFlight/App Store后都能正常工作?
非常感谢任何建议或指导!
备注:内容来源于stack exchange,提问作者BArtWell
相关产品推荐
相关产品推荐

