开发流程

在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-src = { version = "0.1" , features = ["napi-9"]}

ctor = "0.1"

lib.rs 添加测试代码

use std::ffi::{CString};

use std::ptr::{null_mut};

use oh_napi_src::*;

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/index.d.ts

{

"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

修改页面 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

查看原文