You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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.

我的疑问

我有三个问题想请教:

  1. 这是在Compose Multiplatform macOS应用中调用原生函数的正确方式吗?
  2. 应该如何正确签名dylib文件?我现在用的是3rd Party Mac Developer Application身份,这个方式对吗?
  3. 应该如何打包dylib文件,才能让它在Android Studio运行时和发布到TestFlight/App Store后都能正常工作?

非常感谢任何建议或指导!

备注:内容来源于stack exchange,提问作者BArtWell

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.15 10:17:59