在DevEco Studio的模板工程中包含使用Native API的默认工程,使用File->New->Create Project创建Native C++模板工程。
在此基础上进行修改
删除
entry/src/main/cpp
打开
entry/build-profile.json5
删除c++ build 配置
{ "apiType": "stageMode", "buildOption": { // "externalNativeOptions": { // "path": "./src/main/rust/CMakeLists.txt", // "arguments": "", // "cppFlags": "", // } }, "targets": [ { "name": "default", "runtimeOS": "HarmonyOS" }, { "name": "ohosTest", } ] }
创建rust项目
cargo new hello
修改 Cargo.toml
[package] name = "hello" version = "0.1.0" edition = "2021" [lib] name = "hello" crate-type = ["dylib"] [dependencies] oh-napi-sys = "0.1" ctor = "0.1"
lib.rs 添加测试代码
use std::ffi::{CString}; use std::ptr::{null_mut}; use oh_napi_sys::*; use ctor::ctor; extern "C" fn add(env: napi_env, info: napi_callback_info) ->napi_value{ // 期望从ArkTS侧获取的参数的数量,napi_value可理解为ArkTS value在Native方法中的表现形式。 let mut args:[napi_value; 2] = [null_mut();2]; let mut argc = args.len(); unsafe { napi_get_cb_info(env, info, &mut argc, args.as_mut_ptr(), null_mut(), null_mut()); let mut valuetype0 = napi_valuetype_napi_undefined; napi_typeof(env, args[0], &mut valuetype0); let mut valuetype1 = napi_valuetype_napi_undefined; napi_typeof(env, args[1], &mut valuetype1); if (valuetype0 != napi_valuetype_napi_number) || (valuetype1 != napi_valuetype_napi_number) { let mut undefined: napi_value= null_mut(); napi_get_undefined(env, &mut undefined); return undefined; } // 将获取的ArkTS参数转换为Native信息,此处ArkTS侧传入了两个number,这里将其转换为Native侧可以操作的double类型。 let mut value0 = 0f64; napi_get_value_double(env, args[0], &mut value0); let mut value1 = 0f64; napi_get_value_double(env, args[1], &mut value1); // Native侧的业务逻辑,这里简单以两数相加为例。 let native_sum = value0 + value1; // 此处将Native侧业务逻辑处理结果转换为ArkTS值,并返回给ArkTS。 let mut sum = null_mut(); napi_create_double(env, native_sum, &mut sum); return sum; } } type Callback = extern "C" fn(env: napi_env, info: napi_callback_info) -> napi_value; unsafe fn new_func_descriptor(name: &'static str, f: Callback) ->napi_property_descriptor{ let name= CString::new(name).unwrap(); napi_property_descriptor{ utf8name: CString::into_raw(name), name: null_mut(), method: Some(f), getter: None, setter: None, value: null_mut(), attributes: napi_property_attributes_napi_default, data: null_mut(), } } // 注册 module #[ctor] fn register_hello_module(){ let name= CString::new( "hello").unwrap(); let mut hello_module = napi_module{ nm_version: 1, nm_flags: 0, nm_filename: null_mut(), nm_register_func: Some(init), nm_modname: name.as_ptr() as _, nm_priv: 0 as * mut _, reserved: [0 as * mut _;4], }; unsafe { napi_module_register(&mut hello_module); } // Init将在exports上挂上Add/NativeCallArkTS这些Native方法,此处的exports就是开发者import之后获取到的ArkTS对象。 unsafe extern "C" fn init(env: napi_env , exports: napi_value )-> napi_value { let desc =[ new_func_descriptor("add", add), ]; let count = desc.len(); napi_define_properties(env, exports, count, desc.as_ptr()); return exports; } }
添加对应ts代码
// entry/src/main/rust/types/libhello/index.d.ts export const add: (a: number, b: number) => number;
// entry/src/main/rust/types/libhello/oh-package.json5 { "name": "libhello.so", "types": "./index.d.ts", "version": "", "description": "Please describe the basic information." }
配置依赖
// entry/oh-package.json5 { "name": "entry", "version": "1.0.0", "description": "Please describe the basic information.", "main": "", "author": "", "license": "", "dependencies": { "libhello.so": "file:./src/main/rust/types/libhello" } }
在 rust 根目录下编译,添加ohos目标的教程可以参考 Rust交叉编译OpenHarmony应用动态库
cargo build -Zbuild-std --release --target aarch64-unknown-linux-ohos
将编译好的 libhello.so 拷贝至
entry/libs/arm64-v8a
修改页面 Index.ets
import testNapi from 'libhello.so' // onClick 里添加 hilog.info(0x0000, 'testTag', 'Test NAPI 2 + 3 = %{public}d', testNapi.add(2, 3));
编译app点击hello world,日志中看到 Test NAPI 2 + 3 = 5