Kotlin/Native 给鸿蒙使用(一)

2025/02/27 Kotlin KMP 共 16037 字,约 46 分钟

截屏2025-02-26 12.28.50.png

前言

之前在# Kotlin Multiplatform 跨平台支持鸿蒙# Kotlin Multiplatform 封装鸿蒙API介绍了利用 Kotlin/JS 能力支持鸿蒙,通过把逻辑放在 commonMain 中,实现Android:androidMain 、iOS:iosMain 、Harmony:jsMain共享逻辑。在这个过程中,遇到一些限制,比如访问文件,数据库,多线程,多媒体,网络功能等,不能编写出一个共用 API 让 Android, iOS , Harmony 平台都调用,只有定义接口让各平台实现才能适配共享逻辑。为了突破限制,利用 Kotlin/Native 从底层访问系统能力以达到更丝滑,更简单和更容易的方式支持跨平台共享逻辑。

鸿蒙 NDK

要进行 Native 开发,Andrid 有 NDK,鸿蒙也有 NDK

鸿蒙 NDK 前置知识

  • Linux C语言编程知识:内核、libc基础库基于POSIX等标准扩展而来,掌握基本的Linux C编程知识能够更好的帮助理解HarmonyOS NDK开发。

  • CMake使用知识:CMake是HarmonyOS默认支持的构建系统。请先通过CMake官方文档了解基础用法。

  • Node Addons开发知识:ArkTS采用Node-API作为跨语言调用接口,熟悉基本的Node Addons开发模式,可以更好理解NDK中Node-API的使用。

  • Clang/LLVM编译器使用知识:具备一定的Clang/LLVM编译器基础知识,能够帮助开发者编译出更优的Native动态库。

现在需要:复用已有C或C++库,也就是在鸿蒙项目中依赖三方库(*.so)-Kotlin/Native 产物。主要了解一下鸿蒙 Native 通用能力、目标架构 和 Node-API。

通用能力:鸿蒙基于 linux 内核,可以使用 libc,libc++,zlib,OpenGL,以及POSIX 标准等,所以完全支持文件操作、线程、网络等能力。

目标架构:linux_arm64。鸿蒙手机、平板等移动设备使用 arm64 架构。

Node-API:Java/Kotlin 代码与 Native(C/C++)代码进行交互需要 JNI,ArkTS/JS 代码与 Native(C/C++)代码需要 Node-API。

鸿蒙 NDK 和 Android NDK 的角色相似,Node-API 的角色和 JNI 的角色相似。

毕昇编译器简介

毕昇编译器是基于LLVM开源软件开发的一款用于C/C++等语言的native编译器,能将C/C++代码工程编译链接成可以在设备上运行的二进制。在无需改动用户代码的条件下,相比业界主流的开源LLVM或GCC编译器,毕昇编译器能提供更强大的优化能力,使编译链接出来的二进制的运行时长更短、指令数更少,帮助提升应用在设备上的运行流畅度。

如果在鸿蒙中依赖三方库(*.so),那么三方库最好使用毕昇编译器编译。鸿蒙 llvm 路径:/Applications/DevEco-Studio.app/Contents/sdk/default/openharmony/native/llvm

交叉编译时指定 target 和 sysroot:

  • --target=aarch64-linux-ohos参数,通知编译器生成相应架构下符合HarmonyOS ABI的二进制文件:linux_arm64。
  • --sysroot=/Applications/DevEco-Studio.app/Contents/sdk/default/openharmony/native/sysroot 参数,告知编译器HarmonyOS系统头文件的所在位置。

Kotlin/Native

对 Linux 提供的基础能力

Kotlin/Native 对 Linux 提供的基础能力可以在 ~/.konan/kotlin-native-prebuilt-macos-aarch64-2.1.10-RC2/klib 文件目录中找到:

.

├── cache

├── common # 标准库

├── commonized

└── platform # 平台库

common 和 platform 就是 Kotlin/Native 对 Linux 平台提供的基础能力,在 platform 中支持 linux_arm32_hfplinux_arm64linux_x64

下面看下 linux_arm64 目录:

.

├── org.jetbrains.kotlin.native.platform.builtin

├── org.jetbrains.kotlin.native.platform.iconv

├── org.jetbrains.kotlin.native.platform.linux

├── org.jetbrains.kotlin.native.platform.posix

└── org.jetbrains.kotlin.native.platform.zlib
目录作用
org.jetbrains.kotlin.native.platform.builtinC 标准库:内存、数学、字符串处理
org.jetbrains.kotlin.native.platform.iconv字符编码转换
org.jetbrains.kotlin.native.platform.linuxLinux 专用接口:文件监听、高性能 I/O
org.jetbrains.kotlin.native.platform.posixPOSIX 标准接口:文件、线程、网络通信
org.jetbrains.kotlin.native.platform.zlib数据压缩与解压

每个目录其实都是一个 klib(类似于 Java 的 .jar),通过 klib 就能访问这些能力。

org.jetbrains.kotlin.native.platform.posix提供了 platform.posix.* API,通过 import platform.posix.* 就可以访问文件、线程、网络等能力。

通过 @CName 指定导出符号

下载Kotlin/Native 项目模版,将 Kotlin 版本更新到最新(避免 bug)。

首先通过 org.jetbrains.kotlin.native.platform.posix 写一个简单的文件读取 FileUtil.kt

import kotlinx.cinterop.ExperimentalForeignApi
import platform.posix.EOF
import platform.posix.fclose
import platform.posix.fgetc
import platform.posix.fopen
import platform.posix.fputs

@OptIn(ExperimentalForeignApi::class)
fun writeFile(filePath: String, content: String) {
    val file = fopen(filePath, "w") ?: throw Exception("File cannot be opened")
    fputs(content, file)
    fclose(file)
}

@OptIn(ExperimentalForeignApi::class)
fun readFile(filePath: String): String {
    val file = fopen(filePath, "r") ?: throw Exception("File cannot be opened")
    val content = mutableListOf<Char>()
    var c: Int
    while (true) {
        c = fgetc(file)
        if (c == EOF) break
        content.add(c.toChar())
    }
    fclose(file)
    return content.joinToString("")
}

FileUtil.kt 放在 nativeMain 中,可以给 Android, iOS, Harmony 使用。

linuxArm64Main中给 Harmony 使用,新建立一个 HarmonyFileUtil.kt

import kotlin.experimental.ExperimentalNativeApi

@OptIn(ExperimentalNativeApi::class)
@CName("writeFile")
fun harmonyWriteFile(filePath: String, content: String) {
    //调用 FileUtil.kt 的 writeFile
    return writeFile(filePath, content)
}

@OptIn(ExperimentalNativeApi::class)
@CName("readFile")
fun harmonyReadFile(filePath: String): String {
    //调用 FileUtil.kt 的 readFile
    return readFile(filePath)
}

@CName注解的作用是: 使顶层函数可从 C/C++ 代码中访问。

@CName(externName="writeFile")指定导出的符号为:writeFile@CName(externName="readFile")指定导出的符号为:readFile

这里展开稍微简单说下 Android。

通过上一篇# Kotlin/Native 给 Android 使用介绍,在 androidNativeArm64Main 给 Android 使用,新建立一个 AndroidFileUtil.kt

import kotlinx.cinterop.CPointer
import kotlinx.cinterop.ExperimentalForeignApi
import kotlinx.cinterop.cstr
import kotlinx.cinterop.invoke
import kotlinx.cinterop.memScoped
import kotlinx.cinterop.pointed
import kotlinx.cinterop.toKString
import platform.android.JNIEnvVar
import platform.android.jobject
import platform.android.jstring
import kotlin.experimental.ExperimentalNativeApi


@OptIn(ExperimentalForeignApi::class, ExperimentalNativeApi::class)
@CName(externName = "Java_com_wj_mylibrary_NativeLib_readFile")
fun androidReadFile(env: CPointer<JNIEnvVar>, thiz: jobject, filePath: jstring): jstring {
    memScoped {
        val newFilePathJString = env.pointed.pointed!!.GetStringChars!!.invoke(env, filePath, null)
        val newFilePathKString = newFilePathJString?.toKString() ?: ""
        env.pointed.pointed!!.ReleaseStringChars!!.invoke(env, filePath, newFilePathJString)
        //调用 FileUtil.kt 的 readFile
        val result = readFile(newFilePathKString)
        val content = result.cstr.ptr
        return env.pointed.pointed!!.NewStringUTF!!.invoke(
            env, content
        )!!
    }
}

@OptIn(ExperimentalForeignApi::class, ExperimentalNativeApi::class)
@CName(externName = "Java_com_wj_mylibrary_NativeLib_writeFile")
fun androidWriteFile(env: CPointer<JNIEnvVar>, thiz: jobject, filePath: jstring, content: jstring) {
    memScoped {
        val newFilePathJString = env.pointed.pointed!!.GetStringChars!!.invoke(env, filePath, null)
        val newFilePathKString = newFilePathJString?.toKString() ?: ""
        env.pointed.pointed!!.ReleaseStringChars!!.invoke(env, filePath, newFilePathJString)

        val newContentJString = env.pointed.pointed!!.GetStringChars!!.invoke(env, content, null)
        val newContentKString = newContentJString?.toKString() ?: ""
        env.pointed.pointed!!.ReleaseStringChars!!.invoke(env, content, newContentJString)
        //调用 FileUtil.kt 的 writeFile
        writeFile(newFilePathKString, newContentKString)
    }
}

此时, Android 能直接生成符合 JNI 规范的 .so。通过符号Java_com_wj_mylibrary_NativeLib_writeFile 访问 writeFile,通过 Java_com_wj_mylibrary_NativeLib_readFile 符号访问 readFile

回到鸿蒙,鸿蒙是否能直接生成符合 Node-API 规范的 .so?利用 Kotlin/Native 的 C Interop@CName 是可以做到的,这里不做介绍。

编译目标架构

在 build.gradle.kts 中配置:

kotlin {

    //生成linux平台下的 .so
    val linuxTargets = listOf(linuxArm64())
    linuxTargets.forEach {
        it.binaries {
            executable()
            sharedLib {
                //生成 libkn.so
                baseName = "kn"
            }
        }
    }
}

给鸿蒙使用,指定 linuxArm64()即可。

在命令行执行:./gradlew linkReleaseSharedLinuxArm64 --infobuild/bin/linuxArm64/目录下会生成动态库libkn.so和头文件libkn_api.h

.
└── releaseShared
    ├── libkn.so
    └── libkn_api.h

libkn_api.h 头文件中有:

extern "C" {
//...省略

//声明外部函数
extern const char* readFile(const char* filePath);
extern void writeFile(const char* filePath, const char* content);

//...省略

typedef struct {
   //...省略
   //kotlin与c类型映射
  libkn_KBoolean (*IsInstance)(libkn_KNativePtr ref, const libkn_KType* type);
  //...省略
  /* User functions. */
  struct {
    struct {
      const char* (*harmonyReadFile)(const char* filePath);
      void (*harmonyWriteFile)(const char* filePath, const char* content);
      const char* (*readFile_)(const char* filePath);
      void (*writeFile_)(const char* filePath, const char* content);
      void (*main)();
    } root;
  } kotlin;
} libkn_ExportedSymbols;
////声明外部函数:入口
extern libkn_ExportedSymbols* libkn_symbols(void);

}

头文件中,有 kotlin 与 c 的类型映射,比如 c: bool → kotlin: libkn_KBoolean,c: long long → kotlin: libnative_KLong。类型映射关系参看文档# Kotlin/Native as a dynamic library – tutorial

因为添加了 @CName 注解,所以可以直接访问 writeFilereadFile。如果不添加 @CName 注解,可以通过extern libkn_ExportedSymbols* libkn_symbols(void);

libkn_ExportedSymbols* lib = libkn_symbols();

lib->kotlin.root.harmonyWriteFile();

lib->kotlin.root.harmonyReadFile();

访问 harmonyWriteFileharmonyReadFile,达到相同目的。

查看 libkn.so 信息:

file libkn.so

ELF 64-bit LSB shared object, ARM aarch64, version 1 (SYSV), dynamically linked, BuildID[xxHash]=de143ecb6b255574, not stripped

信息表明:libkn.so 是 ARM 64 位架构编译的动态共享库,使用 ELF 格式,遵循System V ABI。库里包含了完整的符号表(未剥离),有唯一的构建 ID,可以通过动态链接加载到其他程序中。

查看 libkn.so 符号:

./aarch64-linux-musl-nm -g libkn.so

...省略
0000000000075048 T readFile
...省略
0000000000075190 T writeFile
...省略

查看 libkn.so 依赖:

./aarch64-linux-musl-readelf -d libkn.so

Dynamic section at offset 0x8f348 contains 32 entries:

  Tag        Type                         Name/Value

 0x0000000000000001 (NEEDED)             Shared library: [libresolv.so.2]

 0x0000000000000001 (NEEDED)             Shared library: [libm.so.6]

 0x0000000000000001 (NEEDED)             Shared library: [libpthread.so.0]

 0x0000000000000001 (NEEDED)             Shared library: [libutil.so.1]

 0x0000000000000001 (NEEDED)             Shared library: [libcrypt.so.1]

 0x0000000000000001 (NEEDED)             Shared library: [librt.so.1]

 0x0000000000000001 (NEEDED)             Shared library: [libdl.so.2]

 0x0000000000000001 (NEEDED)             Shared library: [libgcc_s.so.1]

 0x0000000000000001 (NEEDED)             Shared library: [libc.so.6]

 0x0000000000000007 (RELA)               0x12ce0

 0x0000000000000008 (RELASZ)             100152 (bytes)

 0x0000000000000009 (RELAENT)            24 (bytes)

 0x000000006ffffff9 (RELACOUNT)          3860
 
 //...省略

libkn.so 依赖:

  • libresolv.so.2:DNS 解析库。

  • libm.so.6:数学库(如三角函数、指数运算)。

  • libpthread.so.0:POSIX 线程库(多线程支持)。

  • libutil.so.1:工具函数库。

  • libcrypt.so.1:加密库。

  • librt.so.1:实时扩展库(如定时器、共享内存)。

  • libdl.so.2:动态链接库,支持运行时加载其他共享库。

  • libgcc_s.so.1:GCC 支持库,处理异常、浮点操作。

  • libc.so.6:C 标准库,基础系统调用封装。

在 FileUtil.kt 中只使用了文件操作功能,明显不需要那么多库。

在 gradle.build.kts 中添加按需链接 -as-needed

//生成linux平台下的 .so
val linuxTargets = listOf(linuxArm64())
linuxTargets.forEach {
    it.binaries {
        executable {
            this.compilation.compileTaskProvider.configure {
                this.compilerOptions.freeCompilerArgs.addAll(
                    listOf("-linker-options", "-as-needed")
                )
            }
        }
        sharedLib {
            //生成 libkn.so
            baseName = "kn"
        }
    }
}

freeCompilerArgs 添加的编译选项会交给:

~/.konan/kotlin-native-prebuilt-macos-aarch64-2.1.10-RC2/bin/kotlinc-native -h

//...省略
-linker-option <arg>       Pass the given argument to the linker.
//...省略

编译再看 libkn.so 依赖:

./aarch64-linux-musl-readelf -d libkn.so

Dynamic section at offset 0x8f308 contains 27 entries:

  Tag        Type                         Name/Value

 0x0000000000000001 (NEEDED)             Shared library: [libpthread.so.0]

 0x0000000000000001 (NEEDED)             Shared library: [libdl.so.2]

 0x0000000000000001 (NEEDED)             Shared library: [libgcc_s.so.1]

 0x0000000000000001 (NEEDED)             Shared library: [libc.so.6]
 
  //...省略

因为 Kotlin/Native 在生成 linux_arm64 的 so 时,使用了~/.konan/dependencies/aarch64-unknown-linux-gnu-gcc-8.3.0-glibc-2.25-kernel-4.9-2中的GCC交叉编译工具链,所以依赖GCC的共享库:libgcc_s.so.1

鸿蒙使用毕昇编译器,基于LLVM,libkn.so 不能依赖libgcc_s.so.1(依赖libgcc_s.so.1的libkn.so 在鸿蒙中使用会崩溃)。

要让 libkn.so 不依赖libgcc_s.so.1,选择鸿蒙毕昇编译器交叉编译或静态链接libgcc_s.so.1。这里选择静态链接。

Kotlin/Native 项目构建时,有一个编译工具链配置文件:~/.konan/kotlin-native-prebuilt-macos-aarch64-2.1.10-RC2/konan/konan.properties,在构建 linux_arm64 时,会使用 konan.properties 中有一个配置:linkerGccFlags = -lgcc --as-needed -lgcc_s --no-as-needed -lc -lgcc --as-needed -lgcc_s --no-as-needed,该配置表示:强制链接libgcc_s,所以 libkn.so 才会依赖libgcc_s.so.1

去除依赖libgcc_s.so.1,在 gradle.build.kts 修改 linkerGccFlags:

val linuxTargets = listOf(linuxArm64())
linuxTargets.forEach {
    it.binaries {
        executable {
            entryPoint = "main"
            this.compilation.compileTaskProvider.configure {
                this.compilerOptions.freeCompilerArgs.addAll(
                    listOf(
                        "-Xoverride-konan-properties=linkerGccFlags=-lgcc",
                        "-linker-options", "-as-needed",
                    )
                )
            }
        }
        sharedLib {
            //生成 libkn.so
            baseName = "kn"
        }
    }
}

当然直接在 konan.properties 中修改 linkerGccFlags 也可以。

再编译再看 libkn.so 依赖:

./aarch64-linux-musl-readelf -d libkn.so

Dynamic section at offset 0x8f268 contains 25 entries:

  Tag        Type                         Name/Value

 0x0000000000000001 (NEEDED)             Shared library: [libpthread.so.0]

 0x0000000000000001 (NEEDED)             Shared library: [libdl.so.2]
 
 //...省略

此时,libkn.so 符合要求,可以在鸿蒙中使用。

鸿蒙接入 Kotlin/Native So

首先在鸿蒙项目中创建 Native C++ 模块 khn(任意命名):

截屏2025-02-26 10.41.39.png

将 libkn.so 放在 khn/libs/arm64-v8a/ 目录下,将 libkn_api.h 放在 khn/libs/arm64-v8a/include 目录下。然后修改配置文件 CMakeLists.txt

# the minimum version of CMake.
cmake_minimum_required(VERSION 3.5.0)
project(khn)

set(NATIVERENDER_ROOT_PATH ${CMAKE_CURRENT_SOURCE_DIR})

if(DEFINED PACKAGE_FIND_FILE)
    include(${PACKAGE_FIND_FILE})
endif()

get_filename_component(PROJECT_MAIN_DIR "${CMAKE_CURRENT_SOURCE_DIR}" DIRECTORY)
get_filename_component(PROJECT_SRC_DIR "${PROJECT_MAIN_DIR}" DIRECTORY)
# 获取项目根目录
get_filename_component(PROJECT_DIR "${PROJECT_SRC_DIR}" DIRECTORY)


include_directories(${NATIVERENDER_ROOT_PATH}
                    ${NATIVERENDER_ROOT_PATH}/include)

add_library(khn SHARED napi_init.cpp)
//添加头文件 libkn_api.h
target_include_directories(khn PUBLIC ${PROJECT_DIR}/libs/arm64-v8a/include)
target_link_libraries(khn PUBLIC libace_napi.z.so)
//添加动态库 libkn.so
target_link_libraries(khn PUBLIC ${PROJECT_DIR}/libs/arm64-v8a/libkn.so)

接下来在napi_init.cpp中利用 Node_API 实现 writeFile 和 readFile 功能:

#include "napi/native_api.h"
#include "libkn_api.h"
#include <cstring>

static napi_value NAPI_Global_writeFile(napi_env env, napi_callback_info info) {
    size_t argc = 2;
    napi_value args[2] = {nullptr};
    napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
    // 获取字符串的长度
    size_t filePathLength = 0;
    napi_get_value_string_utf8(env, args[0], nullptr, 0, &filePathLength);
    char *filePath = new char[filePathLength + 1];
    std::memset(filePath, 0, filePathLength + 1);
    napi_get_value_string_utf8(env, args[0], filePath, filePathLength + 1, &filePathLength);
    // 获取字符串的长度
    size_t contentLength = 0;
    napi_get_value_string_utf8(env, args[1], nullptr, 0, &contentLength);
    char *content = new char[contentLength + 1];
    std::memset(content, 0, contentLength + 1);
    napi_get_value_string_utf8(env, args[1], content, contentLength + 1, &contentLength);
    // 调用 libkn.so 中的 writeFile
    writeFile(filePath, content);
    // 或使用下面代码也可以
    // libkn_ExportedSymbols *lib = libkn_symbols();
    // lib->kotlin.root.harmonyWriteFile(filePath, content);

    delete[] filePath;
    delete[] content;
    return nullptr;
}
static napi_value NAPI_Global_readFile(napi_env env, napi_callback_info info) {
    size_t argc = 1;
    napi_value args[1] = {nullptr};
    napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
    // 获取字符串的长度
    size_t filePathLength = 0;
    napi_get_value_string_utf8(env, args[0], nullptr, 0, &filePathLength);
    char *filePath = new char[filePathLength + 1];
    std::memset(filePath, 0, filePathLength + 1);
    napi_get_value_string_utf8(env, args[0], filePath, filePathLength + 1, &filePathLength);
    // 调用 libkn.so 中的 readFile
    const char *content = readFile(filePath);
    // 或使用下面代码也可以
    // libkn_ExportedSymbols *lib = libkn_symbols();
    // const char *content = lib->kotlin.root.harmonyReadFile(filePath);

    napi_value result = nullptr;
    napi_status status = napi_create_string_utf8(env, content, strlen(content), &result);
    delete[] filePath;
    if (status != napi_ok) {
        return nullptr;
    };
    return result;
}

EXTERN_C_START
static napi_value Init(napi_env env, napi_value exports) {
    napi_property_descriptor desc[] = {
        {"writeFile", nullptr, NAPI_Global_writeFile, nullptr, nullptr, nullptr, napi_default, nullptr},
        {"readFile", nullptr, NAPI_Global_readFile, nullptr, nullptr, nullptr, napi_default, nullptr}};
    napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc);
    return exports;
}
EXTERN_C_END

static napi_module demoModule = {
    .nm_version = 1,
    .nm_flags = 0,
    .nm_filename = nullptr,
    .nm_register_func = Init,
    .nm_modname = "khn",
    .nm_priv = ((void *)0),
    .reserved = {0},
};

extern "C" __attribute__((constructor)) void RegisterKhnModule(void) { napi_module_register(&demoModule); }

通过#include "libkn_api.h"访问 writeFile 和 readFile 或 harmonyWriteFile 和 harmonyReadFile。

实现功能后,在 khn/src/main/cpp/types/libkhn/Index.d.ts 定义方法导出:

export const writeFile: (filePath: string, content: string) => void;
export const readFile: (filePath: string) => string;

在 khn/src/main/ets/pages/KotlinNative.ets 再包装一下(也可以不包装):

import { readFile, writeFile } from 'libkhn.so';

export function nativeWriteFile(filePath: string, content: string): void {
  writeFile(filePath, content);
}

export function nativeReadFile(filePath: string): string {
  return readFile(filePath);
}

将 KotlinNative.ets 给其它模块使用,khn/Index.ets:

export * from './src/main/ets/pages/KotlinNative'

鸿蒙项目中任意模块依赖 khn 模块:

"dependencies": {
  "khn": "file:../khn",
},

在模块中使用(测试代码):

import { hilog } from '@kit.PerformanceAnalysisKit'
import { common } from '@kit.AbilityKit'
import { fileIo as fs } from '@kit.CoreFileKit'

// 获取应用文件路径
let context = getContext(this) as common.UIAbilityContext;
let filesDir = context.filesDir;

@Entry
@Component
struct Index {
  build() {
    Column() {
      Button("Kotlin/Native")
        .fontSize(14)
        .fontColor(Color.White)
        .backgroundColor(0xFF60DDAD)
        .width(160)
        .height(60)
        .onClick(() => {
          const path = filesDir + "/test.txt"
          hilog.info(0, "Native", "path=" + path)
          fs.open(path, fs.OpenMode.CREATE).then(() => {
            nativeWriteFile(path, "Hello Kotlin/Native, This is Harmony!")
            const content = nativeReadFile(path)
            hilog.info(0, "Native", "content=" + content)
          }).catch((e: Error) => {
            hilog.error(0, "Native", e.message)
          })
        }) }.alignItems(HorizontalAlign.Center).justifyContent(FlexAlign.Center).width("100%").height('100%')
  }
}

点击 Button Kotlin/Native,在 Device File Browser 中查看:

截屏2025-02-26 12.28.50.png

可以看到 Kotlin/Native 生成的 libkn.so 在 Harmony 平台成功运行。

总结

通过 Kotlin/Native 直接访问系统底层文件,网络,多媒体,多线程等功能,可以突破 Kotlin/Android, Kotlin/iOS, Kotlin/JS 上层的限制,达到真正的一个API在 Android, iOS, Harmony 平台使用,而且还能保证良好的性能。

在 Kotlin/Native 给鸿蒙使用的过程中,由于 Kotlin/Native 构建 linux_arm64 与 鸿蒙 Native 构建 linux_arm64 编译工具链的不同,导致 Kotlin/Native 生成的动态库在鸿蒙平台运行会有找不到符号,找不到依赖库的问题,虽然在去除依赖上能解决问题,但是最好还是可以使用鸿蒙 NDK 编译工具链进行交叉编译。

文档信息

Search

    Table of Contents