前言
此文代碼版本為 code-v3.1-Beta。
2022/05/22 更新:oh 官方提供了一個插件用來一鍵生成 NAPI 框架代碼、業務代碼框架、GN 文件等。因此你也許沒有必要看本文。
https://gitee.com/openharmony/napi_generator#https://gitee.com/openharmony/napi_generator/blob/master/docs/INSTRUCTION_ZH.md
“本文主要介紹NAPI框架代碼生成工具,它可以根據用戶指定路徑下的ts(typescript)接口文件一鍵生成NAPI框架代碼、業務代碼框架、GN文件等。在開發JS應用與NAPI間接口時,底層框架開發者無需關注Nodejs語法、C++與JS之間的數據類型轉換等上層應用轉換邏輯,只關注底層業務邏輯即可,專業的人做專業的事,從而可以大大提高開發效率?!?/p>
NAPI 是什么
類似于 Android 中使用的 JNI,OH 中的 N-API 定義了的由 JS/ETS 語言編寫的代碼編繹出的字節碼和 native 代碼(使用 C/C++ 編寫)交互的方式,由 Node.js N-API 框架擴展而來。
簡單來說,OH 系統中的 NAPI 定義了 JS 代碼和 C++ 代碼的交互方式。
JNI:Java Native Interface;
N-API:Native Application Programming Interface;
Android 中使用的 JNI(Java Native Interface):定義了由 Java 或 Kotlin 語言編寫的代碼編譯出的字節碼和 native 代碼(使用 C/C++ 編寫)交互的方式。
NAPI 設計思想
1. 方舟編譯器(ArkCompiler)將 JS 代碼編繹成 abc 文件,并執行
方舟編譯器(ArkCompiler)中的 ArkCompiler JS Runtime 模塊中的 JS 編譯工具鏈會將 JS 代碼轉換成方舟字節碼即 abc 文件。然后方舟編譯器中的 JS Runtime 會直接運動字節碼文件,實現對應的語義邏輯。其中的 JS-NAPI 模塊將實現 JSNAPI 接口和 C++ 的交互。
2. ArkCompiler 中的 JS-NAPI 模塊調用 Native 代碼注冊的 JS 接口實現代碼(callback method handle)
3. Native 代碼以 property 的形式注冊 callback method handle, 并且在 callback method 中有一個參數用于存放 JS 方法傳入的參數值
如一個 js 對象對應的 native 對象 object,native 代碼將把 object 中的方法、變量、常量構成 [key:methodname,value:callback method handle] 的 property 形式注冊。
如:JS 的 call 接口 @ohos.telephony.call.d.ts 中對應的方法 dial()、變量 callstate、常量 CALL_STATE_IDLE,native 代碼將為其注冊 call 的 properties:["dial",callback method]、["callstate",getter/setter callback method]、["CALL_STATE_IDLE", callback value]
4. native 代碼調用 napi 創建 JS 的 Promise,當 callback method 執行完成后,通過 napi 調用 Promise.resolve(value) 方法向 JS 代碼返回結果。
NAPI 數據類型和封裝函數
napi 數據類型作為 js 數據類型和 c++ 數據類型之間的橋梁,可以和 ArkComplier 中翻譯的 js 數據類型,及 c++ 數據類型相互轉換。napi 框架提供方法實現它們之間的互相轉換。
可參考 Node.js v8.x 中文文檔 ,oh 中的具體實現在 native_api.cpp。
其中基本的數據類型,如 :
- napi_env 對應 NativeEngine 在 oh 中指 ArkComplier 中 JSNAPI 的相關上下文環境,任何 napi 數據類型和 js 數據類型的轉換都需要用到它。
- napi_value 對應 NativeValue 在 oh 中指所有 ArkComplier 可識別的 js 數據類型,它有子類 ArkNativeNumber、ArkNativeString、ArkNativeFunction 等,對應 js 中的 number、string、function 等數據類型。
- napi_callback_info 對應 NativeCallbackInfo ,指注冊 callback handle 時用來存放 js 傳入參數信息的數據類型。它是一個 struct。
- napi_property_descriptor 是用來存放單個 property 的數據類型。
- napi_callback 對應 NativeCallback,即前面的 callback handle,native 代碼將其注冊為對應 js 接口的回調函數。
typedef napi_value (*napi_callback)(napi_env env, napi_callback_info info)
其中基本的轉換函數,如:
- 將 c++ 轉換成 napi 的函數: napi_create_string_utf8 等;
- 將 napi 轉換成 c++ 的函數: napi_get_value_string_utf8 等;
- 創建編譯器中的 js 對象: napi_create_function 等;
- 回調 js 函數:napi_call_function
使用 NAPI
使用 napi 時只要完成以下幾個步驟:
1. 向系統注冊我們要實現的 js 接口對象(在 oh 中指要新增的子系統)
分為以下幾步:
首先:
BUILD.gn 中聲明 js 接口對象 object :ohos_shared_libarary("object")
其次:
通過 napi_module_register 注冊 module
最后:
定義 napi_module ,注冊 module 中 object 的 properties
2. 注冊我們要提供的子系統接口的 properties
首先,定義所有的常量、變量、方法 property:
DECLARE_NAPI_FUNCTION("methodName", NativeMethod);
然后,注冊所有 properties
通過 napi_define_properties 注冊 object 的 properties
3. 實現所有 property 中的回調方法:
從 napi_callback_info 中取出 JS 調用時傳入的所有參數,
并調用 napi 方法將其從 napi 數據類型的值 napi_value 轉換成 native 數據類型的值