开发流程
在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