mirror of
https://gitee.com/openharmony/napi_generator
synced 2024-11-26 18:20:35 +00:00
Merge branch 'master' of gitee.com:openharmony/napi_generator into master
Signed-off-by: 苟晶晶 <goujingjing@kaihong.com>
This commit is contained in:
commit
8ff4a7b781
541
examples/akitutorials/README.md
Normal file
541
examples/akitutorials/README.md
Normal file
@ -0,0 +1,541 @@
|
||||
#### AKI 版 NativeC++ 应用示例
|
||||
|
||||
##### AKI简介
|
||||
|
||||
AKI (Alpha Kernel Interacting) 是一款边界性编程体验友好的ArkTs FFI开发框架,针对OpenHarmony Native开发提供JS与C/C++跨语言访问场景解决方案。支持极简语法糖使用方式,简洁代码逻辑完成JS与C/C++的无障碍跨语言互调。
|
||||
|
||||
简单讲,AKI就是对NAPI进行了一层封装,提供对典型应用场景的包装,减轻了用户开发NAPI层的开发负担,具体优点如下:
|
||||
|
||||
* 解耦FFI代码与业务代码,友好的边界性编程体验;
|
||||
|
||||
* 提供数据类型转换、函数绑定、对象绑定、线程安全等特性;
|
||||
|
||||
* 支持JS & C/C++互调
|
||||
* 支持与Node-API即NAPI的嵌套使用
|
||||
|
||||
|
||||
|
||||
##### AKI代码样例
|
||||
|
||||
* Native C/C++ 业务代码:
|
||||
|
||||
```c++
|
||||
#include <string>
|
||||
#include <aki/jsbind.h>
|
||||
|
||||
std::string SayHello(std::string msg) { return msg + " too."; }
|
||||
|
||||
// Step 1 注册 AKI 插件
|
||||
JSBIND_ADDON(hello) // 注册 AKI 插件名: 即为编译*.so名称,规则与NAPI一致
|
||||
|
||||
// Step 2 注册 FFI 特性
|
||||
JSBIND_GLOBAL() { JSBIND_FUNCTION(SayHello); }
|
||||
```
|
||||
|
||||
* ArkTS 业务代码:
|
||||
|
||||
```typescript
|
||||
import aki from 'libentry.so';
|
||||
let msg = aki.SayHello("hell to cpp");
|
||||
```
|
||||
|
||||
参考:https://gitee.com/openharmony-sig/aki
|
||||
|
||||
|
||||
|
||||
##### 工程调试
|
||||
|
||||
* 使用DevEco Studio Next Release,Build Version: 5.0.3.900, built on October 8, 2024
|
||||
|
||||
* 使用5.0.0 Release 镜像,在rk3568上运行测试
|
||||
|
||||
* 使用[资源](https://gitee.com/openharmony/napi_generator/releases/download/%E6%B5%8B%E8%AF%95%E7%94%A8%E8%B5%84%E6%BA%90/akitutorial_package.zip)内的文件分别拷贝到对应路径(解压后thirdparty内容拷贝到akitutorials\entry\src\main\cpp\thirdparty下,libs里的内容拷贝到akitutorials\entry\libs下)
|
||||
|
||||
* 编译运行
|
||||
|
||||
|
||||
|
||||
##### AKI 接口说明
|
||||
|
||||
* **binding.h**:提供提供函数的类的注册方法,对应JSBIND_FUNCTION,JSBIND_CLASS
|
||||
|
||||
* c++代码:
|
||||
|
||||
```c++
|
||||
#include <string>
|
||||
#include <aki/jsbind.h>
|
||||
|
||||
std::string SayHello(std::string msg)
|
||||
{
|
||||
return msg + " too.";
|
||||
}
|
||||
|
||||
JSBIND_GLOBAL()
|
||||
{
|
||||
JSBIND_FUNCTION(SayHello);
|
||||
}
|
||||
|
||||
JSBIND_ADDON(hello);
|
||||
```
|
||||
|
||||
|
||||
|
||||
* js代码:
|
||||
|
||||
```js
|
||||
import aki from 'libhello.so' // 插件名
|
||||
|
||||
let message = aki.SayHello("hello world");
|
||||
```
|
||||
|
||||
|
||||
|
||||
* **jsbind.h**:提供将JS方法绑定至C/C++层使用的能力。使用JSBind类,提供bindFunction,unbindFunction方法,支持JS线程安全函数注册和使用。如:JSBind.bindFunction,aki::JSBind::GetJSFunction,如:
|
||||
|
||||
* c++ 代码:
|
||||
|
||||
```c++
|
||||
#include <string>
|
||||
#include <aki/jsbind.h>
|
||||
|
||||
void DoSomething() {
|
||||
// 索引 JS 函数句柄
|
||||
auto jsFunc = aki::JSBind::GetJSFunction("sayHelloFromJS");
|
||||
|
||||
// Invoke 指定 JS 方法的返回值类型
|
||||
auto result = jsFunc->Invoke<std::string>("hello from C++"); // 可在非JS线程执行
|
||||
// result == "hello from JS"
|
||||
}
|
||||
```
|
||||
|
||||
* js 代码:
|
||||
|
||||
```js
|
||||
import libAddon from 'libhello.so' // 插件名
|
||||
|
||||
function sayHelloFromJS (value) {
|
||||
console.log('what do you say: ' + value);
|
||||
return "hello from JS"
|
||||
}
|
||||
|
||||
libAddon.JSBind.bindFunction("sayHelloFromJS", sayHelloFromJS);
|
||||
```
|
||||
|
||||
|
||||
|
||||
* **version.h**: 提供aki版本号,如:
|
||||
|
||||
* c++ 代码:
|
||||
|
||||
```c++
|
||||
std::string version(aki::Version::GetVersion());
|
||||
```
|
||||
|
||||
|
||||
|
||||
* **value.h**:提供对value类型的转换,即提供通用类型转换(类似napi_value),Value支持string,number,array等类型,也可通过globalThis拿到对应js句柄,在c++测执行对应方法,如:
|
||||
|
||||
* c++ 代码:
|
||||
|
||||
```c++
|
||||
aki::Value FromGlobalJSONStringify(aki::Value obj) {
|
||||
// 获取js引入的JSON库
|
||||
aki::Value json = aki::Value::FromGlobal("JSON");
|
||||
// 执行JSON.stringify方法将obj输出为json_string
|
||||
return json["stringify"](obj);
|
||||
}
|
||||
```
|
||||
|
||||
* js 代码:
|
||||
|
||||
```js
|
||||
let stringify: string = aki.FromGlobalJSONStringify({
|
||||
'name': 'aki',
|
||||
'age': 1});
|
||||
```
|
||||
|
||||
以上是展示在C++侧获取默认命名空间的方法,还可以自定义,如:
|
||||
|
||||
* c++ 代码:
|
||||
|
||||
```c++
|
||||
std::string SayHello(std::string msg) {
|
||||
std::string version(aki::Version::GetVersion());
|
||||
aki::Value buf = aki::Value::FromGlobal("buffer");
|
||||
aki::Value bufObj = buf["alloc"](10, "a");
|
||||
aki::Value isBuffer = buf["isBuffer"](bufObj);
|
||||
bool isBuf = isBuffer.As<bool>();
|
||||
std::string res = isBuf ? "true" : "false";
|
||||
return msg + " too." + version + res;
|
||||
}
|
||||
```
|
||||
|
||||
* js 代码:注意,必须是ts文件,如果ets文件,编译报错不支持globalThis
|
||||
|
||||
```js
|
||||
import buffer from '@ohos.buffer';
|
||||
|
||||
export class Test {
|
||||
static setBuffer(){
|
||||
globalThis.buffer = buffer;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
* 异步开发:
|
||||
|
||||
* cpp 代码:
|
||||
|
||||
```c++
|
||||
static aki::Promise ReturnPromiseResolveLater()
|
||||
{
|
||||
aki::Promise promise;
|
||||
|
||||
std::thread t([promise] () {
|
||||
aki::TaskRunner::PostTask("main", [promise] () {
|
||||
promise.Resolve(1);
|
||||
});
|
||||
});
|
||||
t.detach();
|
||||
return promise;
|
||||
}
|
||||
```
|
||||
|
||||
* js 代码:
|
||||
|
||||
```js
|
||||
libPromise.JSBind.initTaskRunner("main");
|
||||
libPromise.ReturnPromiseResolveLater().then((value) => {
|
||||
console.log('[AKI] ReturnPromiseResolveLater then: ' + value);
|
||||
})
|
||||
```
|
||||
|
||||
|
||||
|
||||
*
|
||||
|
||||
* 混合开发:即用aki也用napi
|
||||
|
||||
* cpp 代码:
|
||||
|
||||
```c++
|
||||
#include "napi/native_api.h"
|
||||
#include <aki/jsbind.h>
|
||||
|
||||
static napi_value addByNAPI(napi_env env, napi_callback_info info) {
|
||||
......
|
||||
return sum;
|
||||
}
|
||||
|
||||
EXTERN_C_START
|
||||
static napi_value Init(napi_env env, napi_value exports) {
|
||||
napi_property_descriptor desc[] = {
|
||||
{"addByNAPI", nullptr, addByNAPI, nullptr, nullptr, nullptr, napi_default, nullptr}};
|
||||
napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc);
|
||||
|
||||
exports = aki::JSBind::BindSymbols(env, exports); // aki::BindSymbols 函数传入 js 对象绑定符号
|
||||
return exports;
|
||||
}
|
||||
EXTERN_C_END
|
||||
|
||||
// napi 方式的native绑定
|
||||
static napi_module demoModule = {
|
||||
.nm_version = 1,
|
||||
.nm_flags = 0,
|
||||
.nm_filename = nullptr,
|
||||
.nm_register_func = Init,
|
||||
.nm_modname = "entry",
|
||||
.nm_priv = ((void *)0),
|
||||
.reserved = {0},
|
||||
};
|
||||
|
||||
extern "C" __attribute__((constructor)) void RegisterHelloModule(void) { napi_module_register(&demoModule); }
|
||||
|
||||
// aki 方式的native绑定
|
||||
std::string SayHello(std::string msg) {
|
||||
return msg + " too.";
|
||||
}
|
||||
|
||||
// Step 1 注册 AKI 插件
|
||||
JSBIND_ADDON(hello) // 注册 AKI 插件名: 即为编译*.so名称,规则与NAPI一致
|
||||
|
||||
// Step 2 注册 FFI 特性
|
||||
JSBIND_GLOBAL() {
|
||||
JSBIND_FUNCTION(SayHello);
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
* js 代码:
|
||||
|
||||
```js
|
||||
import aki from 'libentry.so';
|
||||
|
||||
let msg: string = aki.SayHello("hell to cpp");
|
||||
hilog.info(0x0000, 'testTag', 'Test SayHello = %{public}s', msg);
|
||||
let res: number = aki.addByNAPI(2, 3);
|
||||
hilog.info(0x0000, 'testTag', 'Test NAPI 2 + 3 = %{public}d', res);
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
##### 实现原理:
|
||||
|
||||
aki 还是利用node-api技术提供 js 和 cpp 间跨语言的交互接口,主要用于开发针对ArkTS的c/c++插件,帮助开发者在ArkTS(ts)中调用本地代码,c/c++库,同时保证跨版本兼容性;
|
||||
|
||||
##### N-API 主要特点
|
||||
|
||||
1. **跨版本兼容性**:N-API 提供了一个稳定的 ABI(应用程序二进制接口),这意味着扩展可以在不同版本的 Node.js 上运行,而无需重新编译或修改代码。
|
||||
2. **简化开发**:N-API 抽象了一些底层的细节,使得开发者可以专注于应用逻辑,而不必担心 Node.js 内部的实现。
|
||||
3. **性能优化**:通过使用本地代码,N-API 可以提高性能,特别是在需要进行大量计算或处理复杂数据结构的情况下。
|
||||
4. **安全性**:N-API 提供了一些安全机制,帮助开发者预防常见的内存管理问题,如缓冲区溢出等。
|
||||
|
||||
##### 使用场景
|
||||
|
||||
- **性能敏感的应用**:例如,大量数据处理、图像处理、加密和解密等。
|
||||
- **需要访问底层系统功能**:如文件系统、网络协议等。
|
||||
- **重用已有的 C/C++ 库**:如果有成熟的 C/C++ 库,可以通过 N-API 将其封装成 Node.js 模块进行使用。
|
||||
|
||||
|
||||
|
||||
1. 依赖库:[CMake参考](https://gitee.com/wshikh/aki/blob/master/src/CMakeLists.txt)
|
||||
|
||||
```cmake
|
||||
target_link_libraries(${TARGET_NAME} PUBLIC libace_napi.z.so libhilog_ndk.z.so uv)
|
||||
```
|
||||
|
||||
2. 编译配置:[CMake参考](https://gitee.com/wshikh/aki/blob/master/src/CMakeLists.txt)
|
||||
|
||||
```cmake
|
||||
//CMakeLists.txt
|
||||
option(AKI_BUILDING_SHARED "compile for shared library" ON)
|
||||
option(AKI_ENABLE_NAPI "using node-api" ON)
|
||||
option(AKI_ENABLE_INSTALL_OHOS "" OFF)
|
||||
option(AKI_ENABLE_DECLARATION "" OFF)
|
||||
option(AKI_ENABLE_TRACING "DO NOT USE THIS option !!!" OFF)
|
||||
option(AKI_ENABLE_CXX_STANDARD_11 "" OFF)
|
||||
```
|
||||
|
||||
3. napi 注册
|
||||
|
||||
* N-API 注册方法:声明模块,利用 napi 接口进行注册
|
||||
|
||||
```cpp
|
||||
// 初始化导出模块的属性描述符
|
||||
EXTERN_C_START
|
||||
static napi_value Init(napi_env env, napi_value exports)
|
||||
{
|
||||
napi_property_descriptor desc[] = {
|
||||
{ "add", nullptr, Add, 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 = "entry",
|
||||
.nm_priv = ((void*)0),
|
||||
.reserved = { 0 },
|
||||
};
|
||||
|
||||
// 注册模块(也可以称之为 c/c++插件)
|
||||
extern "C" __attribute__((constructor)) void RegisterEntryModule(void)
|
||||
{
|
||||
napi_module_register(&demoModule);
|
||||
}
|
||||
```
|
||||
|
||||
* aki 注册方法:
|
||||
|
||||
```cpp
|
||||
// Step 1 注册 AKI 插件
|
||||
JSBIND_ADDON(hello) // 注册 AKI 插件名: 即为编译*.so名称,规则与NAPI一致
|
||||
|
||||
// Step 2 注册 FFI 特性
|
||||
JSBIND_GLOBAL() {
|
||||
JSBIND_FUNCTION(SayHello);
|
||||
JSBIND_FUNCTION(FromGlobalJSONStringify);
|
||||
}
|
||||
```
|
||||
|
||||
* JSBIND_ADDON:
|
||||
|
||||
```c
|
||||
#define JSBIND_ADDON_LAZY(addonName) \
|
||||
EXTERN_C_START \
|
||||
static napi_module _module = { \
|
||||
.nm_version =1, \
|
||||
.nm_flags = 0, \
|
||||
.nm_filename = nullptr, \
|
||||
.nm_register_func = aki::JSBind::BindSymbols, \
|
||||
.nm_modname = #addonName, \
|
||||
.nm_priv = ((void*)0), \
|
||||
.reserved = { 0 }, \
|
||||
}; \
|
||||
extern "C" __attribute__((constructor)) void Register##addonName(void) { \
|
||||
napi_module_register(&_module); \
|
||||
AKI_LOG(INFO) << "register AKI addon: " << #addonName; \
|
||||
} \
|
||||
EXTERN_C_END
|
||||
|
||||
#define JSBIND_ADDON(addonName) \
|
||||
JSBIND_ADDON_LAZY(addonName)
|
||||
```
|
||||
|
||||
|
||||
|
||||
* JSBIND_GLOBAL:
|
||||
|
||||
```c
|
||||
// 宏定义,JSBIND_GLOBAL 转 namespace
|
||||
#define JSBIND_GLOBAL() namespace
|
||||
|
||||
// 宏定义,JSBIND_FUNCTION 转 aki::FunctionDefiner,变量名就是definer+__LINE__,后面执行的是FunctionDefiner构造函数
|
||||
#define JSBIND_FUNCTION(__name, ...) aki::FunctionDefiner JSBIND_UNIQUE(definer, __LINE__)(aki::AliasName(#__name, ##__VA_ARGS__), &__name)
|
||||
|
||||
// 宏定义,JSBIND_FUNCTION 转 aki::PFunctionDefiner,变量名就是definer+__LINE__,后面执行的是PFunctionDefiner构造函数
|
||||
#define JSBIND_PFUNCTION(__name, ...) aki::PFunctionDefiner JSBIND_UNIQUE(definer, __LINE__)(aki::AliasName(#__name, ##__VA_ARGS__), &__name)
|
||||
```
|
||||
|
||||
|
||||
|
||||
* FunctionDefiner & Init:
|
||||
|
||||
```c++
|
||||
namespace aki {
|
||||
class FunctionDefiner {
|
||||
public:
|
||||
......
|
||||
// 注册方法
|
||||
Binding::RegisterFunction(name, Binder::AddInvoker(func), &Binder::GetInstance());
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
* BindSymbols
|
||||
|
||||
```c++
|
||||
// 对应的就是导出模块里的注册方法: .nm_register_func = aki::JSBind::BindSymbols,
|
||||
napi_value aki::JSBind::BindSymbols(napi_env env, napi_value exports)
|
||||
{
|
||||
return Init(env, exports);
|
||||
}
|
||||
|
||||
EXTERN_C_START
|
||||
static napi_value Init(napi_env env, napi_value exports) {
|
||||
......
|
||||
for (auto& function : aki::Binding::GetFunctionList()) {
|
||||
auto akibinder = function.GetBinder();
|
||||
auto wrapper = reinterpret_cast<NapiWrapperFunctionInfo>(akibinder->GetWrapper());
|
||||
|
||||
napi_status status;
|
||||
aki::BindInfo* info = new aki::BindInfo();
|
||||
info->functionNumber = function.GetInvokerId();
|
||||
// 定义function描述符
|
||||
napi_property_descriptor desc = DECLARE_NAPI_FUNCTION(function.GetName(), wrapper, info);
|
||||
// 在导出对象里增加方法属性
|
||||
status = napi_define_properties(env, exports, 1, &desc);
|
||||
AKI_DCHECK(status == napi_ok) << "napi_define_properties failed when binding global function: " << function.GetName();
|
||||
AKI_DLOG(DEBUG) << "binding global function: " << function.GetName();
|
||||
}
|
||||
|
||||
// 下面还有对 Enumeration 和 Class 的注册
|
||||
for (auto& enumeration : aki::Binding::GetEnumerationList()) {
|
||||
......
|
||||
}
|
||||
|
||||
for (auto& xlass : aki::Binding::GetClassList()) {
|
||||
......
|
||||
}
|
||||
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
* 默认注册类 JSBind:提供native直接调用js函数的方法和执行js的线程任务,其特点有:
|
||||
|
||||
* 线程安全:可在非JS线程直接调用。最终会由框架调度JS线程执行业务;
|
||||
* 阻塞式调用:在非JS线程时存在跨线程任务调度。 C++ 会等待 JavaScript 函数执行结束后返回;
|
||||
|
||||
```c++
|
||||
namespace aki {
|
||||
class AKI_EXPORT JSBind {
|
||||
public:
|
||||
#if JSBIND_USING_NAPI
|
||||
static napi_value BindSymbols(napi_env env, napi_value exports);
|
||||
static napi_value BindSymbols(napi_env env, napi_value exports, std::string moduleName);
|
||||
static napi_value BindSymbols(const char* module);
|
||||
static void SetScopedEnv(napi_env env);
|
||||
static napi_env GetScopedEnv();
|
||||
#endif // JSBIND_USING_NAPI
|
||||
|
||||
static int bindFunction(const std::string& name, JSFunction func);
|
||||
static int unbindFunction(const std::string& name);
|
||||
static void InitTaskRunner(const std::string& name);
|
||||
|
||||
#if JSBIND_SUPPORT_DECLARATION
|
||||
static void Reflect(aki::Callback<void (intptr_t, int32_t)> outputBuildInType,
|
||||
aki::Callback<void (std::string, std::vector<intptr_t>)> outputFunction);
|
||||
static void QueryType(intptr_t typeId,
|
||||
aki::Callback<void (int32_t, std::vector<intptr_t>)> outputType);
|
||||
#endif
|
||||
static const JSFunction* GetJSFunction(const std::string& name);
|
||||
private:
|
||||
};
|
||||
|
||||
// | static |
|
||||
int JSBind::bindFunction(const std::string& name, JSFunction func)
|
||||
{
|
||||
return Binding::RegisterJSFunction(name, std::make_unique<JSFunction>(std::move(func)));
|
||||
}
|
||||
|
||||
int JSBind::unbindFunction(const std::string& name)
|
||||
{
|
||||
return Binding::UnRegisterJSFunction(name);
|
||||
}
|
||||
|
||||
void aki::JSBind::InitTaskRunner(const std::string& name) {
|
||||
aki::TaskRunner::Create(name);
|
||||
}
|
||||
}
|
||||
using namespace aki;
|
||||
JSBIND_CLASS(JSBind) {
|
||||
JSBIND_METHOD(bindFunction);
|
||||
JSBIND_METHOD(unbindFunction);
|
||||
JSBIND_METHOD(InitTaskRunner, "initTaskRunner");
|
||||
|
||||
#if JSBIND_SUPPORT_DECLARATION
|
||||
JSBIND_METHOD(Reflect, "reflect");
|
||||
JSBIND_METHOD(QueryType, "queryType");
|
||||
#endif
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
### 总结
|
||||
|
||||
1. 最新5.0.0 Release 的IDE也能进行开发NativeC++项目,不过要修改工程,参考这个修改:https://forums.openharmony.cn/forum.php?mod=viewthread&tid=3550&page=1#pid8694 ;
|
||||
2. AKI 是一个native应用开发的快速框架,提供了绑定函数,类,枚举给js层使用,以及从native侧获取js全局对象,js方法,js异步任务的方法;给应用开发者提供跨语言的互相访问能力;
|
||||
3. AKI 可以和原来的 napi 开发方式并存,混合使用;
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -66,6 +66,12 @@ add_library(entry SHARED
|
||||
javascriptapi/jsvalues/napicreateint32.cpp
|
||||
javascriptapi/jsvalues/napicreateuint32.cpp
|
||||
javascriptapi/jsvalues/napicreateint64.cpp
|
||||
javascriptapi/jsfunctions/jsFunctionsInit.cpp
|
||||
javascriptapi/jsfunctions/napicallfunction.cpp
|
||||
javascriptapi/jsfunctions/napicreatefunction.cpp
|
||||
javascriptapi/jsobjectwrap/jsObjectWrapInit.cpp
|
||||
javascriptapi/jsobjectwrap/napiwrap.cpp
|
||||
javascriptapi/jsobjectwrap/napiunwrap.cpp
|
||||
ncpp/ffmpegcase/render/egl_core.cpp
|
||||
ncpp/ffmpegcase/render/plugin_render.cpp
|
||||
ncpp/ffmpegcase/manager/plugin_manager.cpp
|
||||
|
@ -58,4 +58,13 @@ napi_value testNapiCreateInt32(napi_env env, napi_callback_info info);
|
||||
napi_value testNapiCreateUInt32(napi_env env, napi_callback_info info);
|
||||
napi_value testNapiCreateInt64(napi_env env, napi_callback_info info);
|
||||
|
||||
napi_value jsFunctionsInit(napi_env env, napi_value exports);
|
||||
napi_value testNapiCallFunction(napi_env env, napi_callback_info info);
|
||||
napi_value SayHello(napi_env env, napi_callback_info info);
|
||||
napi_value testNapiCreateFunction(napi_env env, napi_callback_info info);
|
||||
|
||||
napi_value jsObjectWrapInit(napi_env env, napi_value exports);
|
||||
napi_value testNapiWrap(napi_env env, napi_callback_info info);
|
||||
napi_value testNapiUnwrap(napi_env env, napi_callback_info info);
|
||||
|
||||
#endif //NAPITUTORIALS_JAVASCRIPTAPI_H
|
||||
|
@ -114,6 +114,12 @@ static napi_value Init(napi_env env, napi_value exports)
|
||||
// 对应 javascriptapi/jsproperty/jsPropertyInit.cpp
|
||||
jsPropertyInit(env, exports);
|
||||
|
||||
// 对应 javascriptapi/jsfunctions/jsFunctionsInit.cpp
|
||||
jsFunctionsInit(env, exports);
|
||||
|
||||
// 对应 javascriptapi/jsobjectwrap/jsObjectWrapInit.cpp
|
||||
jsObjectWrapInit(env, exports);
|
||||
|
||||
napi_property_descriptor descArr[] = {
|
||||
{"add", nullptr, Add, nullptr, nullptr, nullptr, napi_default, nullptr},
|
||||
{"getTestCase", nullptr, getTestCase, nullptr, nullptr, nullptr, napi_default, nullptr},
|
||||
|
@ -0,0 +1,27 @@
|
||||
/*
|
||||
* Copyright (c) 2024 Shenzhen Kaihong Digital Industry Development Co., Ltd.
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "common.h"
|
||||
#include "javascriptapi.h"
|
||||
|
||||
napi_value jsFunctionsInit(napi_env env, napi_value exports)
|
||||
{
|
||||
napi_property_descriptor desc[] = {
|
||||
{"testNapiCallFunction", nullptr, testNapiCallFunction, nullptr, nullptr, nullptr, napi_default, nullptr},
|
||||
{"testNapiCreateFunction", nullptr, testNapiCreateFunction, nullptr, nullptr, nullptr, napi_default, nullptr},
|
||||
};
|
||||
napi_define_properties(env, exports, sizeof(desc) / sizeof(napi_property_descriptor), desc);
|
||||
return exports;
|
||||
}
|
@ -0,0 +1,63 @@
|
||||
/*
|
||||
* Copyright (c) 2024 Shenzhen Kaihong Digital Industry Development Co., Ltd.
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "common.h"
|
||||
#include "javascriptapi.h"
|
||||
|
||||
static const char *TAG = "[javascriptapi_function]";
|
||||
|
||||
napi_value testNapiCallFunction(napi_env env, napi_callback_info info)
|
||||
{
|
||||
// pages/javascript/jsfunctions/napicallfunction
|
||||
// 获取参数数量
|
||||
size_t argc = PARAM2;
|
||||
// 准备接收参数的变量
|
||||
napi_value argv[PARAM2];
|
||||
napi_value func;
|
||||
napi_value result;
|
||||
napi_status status;
|
||||
const napi_extended_error_info *extended_error_info;
|
||||
|
||||
// 获取回调函数的参数信息
|
||||
status = napi_get_cb_info(env, info, &argc, argv, NULL, NULL);
|
||||
if (status != napi_ok) {
|
||||
getErrMsg(status, env, extended_error_info, "Failed to get callback info", TAG);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// 检查参数数量是否符合预期
|
||||
if (argc != PARAM2) {
|
||||
napi_throw_error(env, NULL, "Expected exactly one argument");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// 检查传入参数是否为function
|
||||
napi_valuetype resultType;
|
||||
napi_typeof(env, argv[0], &resultType);
|
||||
if (resultType != napi_function) {
|
||||
napi_throw_error(env, NULL, "The incoming parameter is not a function");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
func = argv[PARAM0];
|
||||
status = napi_call_function(env, NULL, func, PARAM1, &argv[PARAM1], &result);
|
||||
if (status != napi_ok) {
|
||||
getErrMsg(status, env, extended_error_info, "call function", TAG);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
@ -0,0 +1,48 @@
|
||||
/*
|
||||
* Copyright (c) 2024 Shenzhen Kaihong Digital Industry Development Co., Ltd.
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "common.h"
|
||||
#include "javascriptapi.h"
|
||||
|
||||
static const char *TAG = "[javascriptapi_function]";
|
||||
|
||||
napi_value SayHello(napi_env env, napi_callback_info info)
|
||||
{
|
||||
printf("Hello\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
napi_value testNapiCreateFunction(napi_env env, napi_callback_info info)
|
||||
{
|
||||
// pages/javascript/jsfunctions/napicreatefunction
|
||||
napi_value func;
|
||||
napi_status status;
|
||||
napi_value obj;
|
||||
const napi_extended_error_info *extended_error_info;
|
||||
|
||||
status = napi_create_object(env, &obj);
|
||||
if (status != napi_ok) {
|
||||
// 错误处理
|
||||
return NULL;
|
||||
}
|
||||
|
||||
status = napi_create_function(env, NULL, 0, SayHello, NULL, &func);
|
||||
if (status != napi_ok) {
|
||||
getErrMsg(status, env, extended_error_info, "create function", TAG);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return func;
|
||||
}
|
@ -0,0 +1,27 @@
|
||||
/*
|
||||
* Copyright (c) 2024 Shenzhen Kaihong Digital Industry Development Co., Ltd.
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "common.h"
|
||||
#include "javascriptapi.h"
|
||||
|
||||
napi_value jsObjectWrapInit(napi_env env, napi_value exports)
|
||||
{
|
||||
napi_property_descriptor desc[] = {
|
||||
{"testNapiWrap", nullptr, testNapiWrap, nullptr, nullptr, nullptr, napi_default, nullptr},
|
||||
{"testNapiUnwrap", nullptr, testNapiUnwrap, nullptr, nullptr, nullptr, napi_default, nullptr}};
|
||||
|
||||
napi_define_properties(env, exports, sizeof(desc) / sizeof(napi_property_descriptor), desc);
|
||||
return exports;
|
||||
}
|
@ -0,0 +1,90 @@
|
||||
/*
|
||||
* Copyright (c) 2024 Shenzhen Kaihong Digital Industry Development Co., Ltd.
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "common.h"
|
||||
#include "javascriptapi.h"
|
||||
#include "hilog/log.h"
|
||||
static const char *TAG = "[javascriptapi_object_wrap]";
|
||||
|
||||
class MyNode {
|
||||
public:
|
||||
napi_status status;
|
||||
napi_valuetype result;
|
||||
napi_value resultStr;
|
||||
const napi_extended_error_info *extended_error_info;
|
||||
MyNode(napi_env env, napi_value val)
|
||||
{
|
||||
// Call napi_typeof(), any -> napi_valuetype
|
||||
status = napi_typeof(env, val, &result);
|
||||
if (status != napi_ok) {
|
||||
getErrMsg(status, env, extended_error_info, "call napi_typeof()", TAG);
|
||||
}
|
||||
|
||||
// napi_valuetype -> string
|
||||
status = napiValueType2Str(env, result, &resultStr);
|
||||
if (status != napi_ok) {
|
||||
std::string errMsg = "Failed to convert napi_valuetype " + std::to_string(status) + " to string";
|
||||
napi_throw_error(env, NULL, errMsg.c_str());
|
||||
}
|
||||
}
|
||||
napi_value GetResult(napi_env env)
|
||||
{
|
||||
return resultStr;
|
||||
}
|
||||
};
|
||||
|
||||
napi_value testNapiUnwrap(napi_env env, napi_callback_info info)
|
||||
{
|
||||
size_t argc = PARAM1;
|
||||
napi_value argv[PARAM1];
|
||||
napi_value thisObj;
|
||||
void *data = nullptr;
|
||||
napi_status status;
|
||||
napi_value cons;
|
||||
const napi_extended_error_info *extended_error_info;
|
||||
// 获取回调函数的参数信息
|
||||
status = napi_get_cb_info(env, info, &argc, argv, &thisObj, &data);
|
||||
if (status != napi_ok) {
|
||||
getErrMsg(status, env, extended_error_info, "Failed to get callback info", TAG);
|
||||
return NULL;
|
||||
}
|
||||
auto instance = new MyNode(env, argv[PARAM0]);
|
||||
status = napi_wrap(
|
||||
env, thisObj, instance,
|
||||
[](napi_env environment, void *data, void *hint) {
|
||||
auto objInfo = reinterpret_cast<MyNode *>(data);
|
||||
if (objInfo != nullptr) {
|
||||
delete objInfo;
|
||||
}
|
||||
}, NULL, NULL);
|
||||
if (status != napi_ok) {
|
||||
getErrMsg(status, env, extended_error_info, "wrap", TAG);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
MyNode *obj;
|
||||
status = napi_unwrap(env, thisObj, reinterpret_cast<void **>(&obj));
|
||||
if (status != napi_ok) {
|
||||
getErrMsg(status, env, extended_error_info, "unwrap", TAG);
|
||||
return NULL;
|
||||
}
|
||||
napi_value resultStrValue = obj->GetResult(env);
|
||||
if (resultStrValue == nullptr) {
|
||||
// 处理错误情况
|
||||
napi_throw_error(env, NULL, "Failed to get result string");
|
||||
return NULL;
|
||||
}
|
||||
return resultStrValue;
|
||||
}
|
@ -0,0 +1,74 @@
|
||||
/*
|
||||
* Copyright (c) 2024 Shenzhen Kaihong Digital Industry Development Co., Ltd.
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "common.h"
|
||||
#include "javascriptapi.h"
|
||||
|
||||
static const char *TAG = "[javascriptapi_object_wrap]";
|
||||
static const int MAX_BUFFER_SIZE = 128;
|
||||
|
||||
class Node {
|
||||
public:
|
||||
Node(napi_env env, napi_value id)
|
||||
{
|
||||
// 将 JavaScript 字符串转换为 C++ 字符串
|
||||
size_t idLength = MAX_BUFFER_SIZE;
|
||||
char buf[MAX_BUFFER_SIZE];
|
||||
char *buffer = buf;
|
||||
napi_get_value_string_utf8(env, id, buffer, idLength, nullptr);
|
||||
// 将 C++ 字符串转换为 std::string
|
||||
_id = std::string(buffer);
|
||||
}
|
||||
std::string GetId() { return _id; }
|
||||
private:
|
||||
std::string _id; // 成员变量,存储 id
|
||||
};
|
||||
|
||||
napi_value testNapiWrap(napi_env env, napi_callback_info info)
|
||||
{
|
||||
size_t argc = PARAM1;
|
||||
napi_value argv[PARAM1] = {0};
|
||||
napi_value thisObj = nullptr;
|
||||
void *data = nullptr;
|
||||
napi_status status;
|
||||
napi_value cons;
|
||||
const napi_extended_error_info *extended_error_info;
|
||||
// 获取回调函数的参数信息
|
||||
status = napi_get_cb_info(env, info, &argc, argv, &thisObj, &data);
|
||||
if (status != napi_ok) {
|
||||
getErrMsg(status, env, extended_error_info, "Failed to get callback info", TAG);
|
||||
return NULL;
|
||||
}
|
||||
napi_valuetype resultType;
|
||||
napi_typeof(env, argv[PARAM0], &resultType);
|
||||
if (resultType != napi_string) {
|
||||
std::string res = "Expected a string, got " + std::to_string(resultType);
|
||||
napi_throw_error(env, NULL, res.c_str());
|
||||
return NULL;
|
||||
}
|
||||
auto instance = new Node(env, argv[PARAM0]);
|
||||
status = napi_wrap(env, thisObj, instance,
|
||||
[](napi_env environment, void *data, void *hint) {
|
||||
auto objInfo = reinterpret_cast<Node *>(data);
|
||||
if (objInfo != nullptr) {
|
||||
delete objInfo;
|
||||
}
|
||||
}, NULL, NULL);
|
||||
if (status != napi_ok) {
|
||||
getErrMsg(status, env, extended_error_info, "wrap", TAG);
|
||||
return NULL;
|
||||
}
|
||||
return thisObj;
|
||||
}
|
@ -65,3 +65,11 @@ export const testNapiStrictEquals: (a: any, b: any) => boolean;
|
||||
export const testNapiCreateInt32: (number) => number;
|
||||
export const testNapiCreateUInt32: (number) => number;
|
||||
export const testNapiCreateInt64: (number) => number;
|
||||
|
||||
/* work_with_javascript_functions */
|
||||
export const testNapiCallFunction: (a: Function, b: number) => number;
|
||||
export const testNapiCreateFunction: () => any;
|
||||
|
||||
/* work_with_javascript_objectwrap */
|
||||
export const testNapiWrap: (a: string) => any;
|
||||
export const testNapiUnwrap: (a: any) => string;
|
@ -400,11 +400,11 @@ const WORK_WITH_JAVASCRIPT_FUNCTIONS: ThirdLevelCategory =
|
||||
childNodes: [
|
||||
{
|
||||
title: $r('app.string.napi_call_function'),
|
||||
url: 'pages/image/basicSample/image2Gray'
|
||||
url: 'pages/javascript/jsfunctions/napicallfunction'
|
||||
},
|
||||
{
|
||||
title: $r('app.string.napi_create_function'),
|
||||
url: 'pages/image/basicSample/image2Gray'
|
||||
url: 'pages/javascript/jsfunctions/napicreatefunction'
|
||||
},
|
||||
{
|
||||
title: $r('app.string.napi_get_cb_info'),
|
||||
@ -432,11 +432,11 @@ const OBJECT_WRAP: ThirdLevelCategory =
|
||||
},
|
||||
{
|
||||
title: $r('app.string.napi_wrap'),
|
||||
url: 'pages/image/basicSample/image2Gray'
|
||||
url: 'pages/javascript/jsobjectwrap/napiwrap'
|
||||
},
|
||||
{
|
||||
title: $r('app.string.napi_unwrap'),
|
||||
url: 'pages/image/basicSample/image2Gray'
|
||||
url: 'pages/javascript/jsobjectwrap/napiunwrap'
|
||||
},
|
||||
{
|
||||
title: $r('app.string.napi_remove_wrap'),
|
||||
|
@ -0,0 +1,109 @@
|
||||
/*
|
||||
* Copyright (c) 2024 Shenzhen Kaihong Digital Industry Development Co., Ltd.
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import router from '@ohos.router';
|
||||
import image from '@ohos.multimedia.image';
|
||||
import Logger from '../../../util/Logger';
|
||||
import testNapi, { testNapiValue } from 'libentry.so';
|
||||
import { TitleBar } from '../../../common/TitleBar'
|
||||
import hilog from '@ohos.hilog';
|
||||
|
||||
const TAG: string = 'napi_call_function';
|
||||
|
||||
function AddTwo(num: number) {
|
||||
return num + 2;
|
||||
}
|
||||
|
||||
@Entry
|
||||
@Component
|
||||
struct napiCallFunction {
|
||||
private btnFontColor: Resource = $r('app.color.white');
|
||||
private pixelMapFormat: image.PixelMapFormat = 3;
|
||||
@State isSetInstance: Boolean = false;
|
||||
@State imagePixelMap: PixelMap | undefined = undefined;
|
||||
@State textcont: string = 'napi_call_function用于从原生附加组件调用 JavaScript 函数对象。'
|
||||
+ '这是从加载项的原生代码回调到 JavaScript 的主要机制。';
|
||||
@State testcont: string = ' // 测试 N-API napi_call_function \n'
|
||||
+ ' let fun = function AddTwo(num) {return num + 2;} \n'
|
||||
+ ' const result = testNapi.testNapiCallFunction(fun, 7); \n'
|
||||
+ ' console.log(result); \n'
|
||||
|
||||
|
||||
controller: TextAreaController = new TextAreaController()
|
||||
|
||||
build() {
|
||||
Column() {
|
||||
// 标题
|
||||
TitleBar({ title: $r('app.string.napi_call_function') })
|
||||
|
||||
Column() {
|
||||
Column() {
|
||||
TextArea({
|
||||
text: this.textcont,
|
||||
placeholder: '',
|
||||
})
|
||||
.placeholderFont({ size: 16, weight: 400 })
|
||||
.width('90%')
|
||||
.margin(10)
|
||||
.fontSize(16)
|
||||
.fontColor($r('app.color.sub_title_color'))
|
||||
.backgroundColor($r('app.color.white'))
|
||||
.enabled(false)
|
||||
|
||||
TextArea({
|
||||
text: this.testcont,
|
||||
placeholder: '',
|
||||
})
|
||||
.placeholderFont({ size: 16, weight: 400 })
|
||||
.width('90%')
|
||||
.margin(10)
|
||||
.fontSize(16)
|
||||
.fontColor($r('app.color.textarea_font_color'))
|
||||
.backgroundColor($r('app.color.white'))
|
||||
.enabled(false)
|
||||
}
|
||||
.width('100%')
|
||||
.alignItems(HorizontalAlign.Center)
|
||||
.justifyContent(FlexAlign.Start)
|
||||
|
||||
Row() {
|
||||
|
||||
Button($r('app.string.napi_call_function'), { type: ButtonType.Capsule })
|
||||
.backgroundColor(Color.Blue)
|
||||
.width('80%')
|
||||
.height(48)
|
||||
.fontSize(16)
|
||||
.fontWeight(500)
|
||||
.fontColor(this.btnFontColor)
|
||||
.margin({ left: 24 })
|
||||
.id('napi_call_function')
|
||||
.onClick(() => {
|
||||
let fun: Function = AddTwo;
|
||||
let ret: number = testNapi.testNapiCallFunction(fun, 7);
|
||||
this.testcont = this.testcont.replace('log(result)', 'log(## ' + ret + ' ##)');
|
||||
})
|
||||
}
|
||||
.width('100%')
|
||||
.height(48)
|
||||
.alignItems(VerticalAlign.Center)
|
||||
.justifyContent(FlexAlign.SpaceBetween)
|
||||
}
|
||||
.width('100%')
|
||||
}
|
||||
.height('100%')
|
||||
.width('100%')
|
||||
.backgroundColor($r('app.color.background_shallow_grey'))
|
||||
}
|
||||
}
|
@ -0,0 +1,103 @@
|
||||
/*
|
||||
* Copyright (c) 2024 Shenzhen Kaihong Digital Industry Development Co., Ltd.
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import router from '@ohos.router';
|
||||
import image from '@ohos.multimedia.image';
|
||||
import Logger from '../../../util/Logger';
|
||||
import testNapi, { testNapiValue } from 'libentry.so';
|
||||
import { TitleBar } from '../../../common/TitleBar'
|
||||
import hilog from '@ohos.hilog';
|
||||
|
||||
const TAG: string = 'napi_create_function';
|
||||
|
||||
@Entry
|
||||
@Component
|
||||
struct napiCreateFunction {
|
||||
private btnFontColor: Resource = $r('app.color.white');
|
||||
private pixelMapFormat: image.PixelMapFormat = 3;
|
||||
@State isSetInstance: Boolean = false;
|
||||
@State imagePixelMap: PixelMap | undefined = undefined;
|
||||
@State textcont: string = 'napi_create_function允许插件作者以原生代码创建函数对象。'
|
||||
+ '这是允许从 JavaScript 调用加载项的原生代码的主要机制。';
|
||||
@State testcont: string = ' // 测试 N-API napi_create_function \n'
|
||||
+ ' const result = testNapi.testNapiCreateFunction(); \n'
|
||||
+ ' console.log(result); \n'
|
||||
|
||||
|
||||
controller: TextAreaController = new TextAreaController()
|
||||
|
||||
build() {
|
||||
Column() {
|
||||
// 标题
|
||||
TitleBar({ title: $r('app.string.napi_create_function') })
|
||||
|
||||
Column() {
|
||||
Column() {
|
||||
TextArea({
|
||||
text: this.textcont,
|
||||
placeholder: '',
|
||||
})
|
||||
.placeholderFont({ size: 16, weight: 400 })
|
||||
.width('90%')
|
||||
.margin(10)
|
||||
.fontSize(16)
|
||||
.fontColor($r('app.color.sub_title_color'))
|
||||
.backgroundColor($r('app.color.white'))
|
||||
.enabled(false)
|
||||
|
||||
TextArea({
|
||||
text: this.testcont,
|
||||
placeholder: '',
|
||||
})
|
||||
.placeholderFont({ size: 16, weight: 400 })
|
||||
.width('90%')
|
||||
.margin(10)
|
||||
.fontSize(16)
|
||||
.fontColor($r('app.color.textarea_font_color'))
|
||||
.backgroundColor($r('app.color.white'))
|
||||
.enabled(false)
|
||||
}
|
||||
.width('100%')
|
||||
.alignItems(HorizontalAlign.Center)
|
||||
.justifyContent(FlexAlign.Start)
|
||||
|
||||
Row() {
|
||||
|
||||
Button($r('app.string.napi_create_function'), { type: ButtonType.Capsule })
|
||||
.backgroundColor(Color.Blue)
|
||||
.width('80%')
|
||||
.height(48)
|
||||
.fontSize(16)
|
||||
.fontWeight(500)
|
||||
.fontColor(this.btnFontColor)
|
||||
.margin({ left: 24 })
|
||||
.id('napi_create_function')
|
||||
.onClick(() => {
|
||||
console.log(`result is ${testNapi.testNapiCreateFunction()}`);
|
||||
this.testcont = this.testcont.replace('log(result)', 'log(## typeof result is ' + typeof (testNapi.testNapiCreateFunction()) + ' ##)');
|
||||
})
|
||||
}
|
||||
.width('100%')
|
||||
.height(48)
|
||||
.alignItems(VerticalAlign.Center)
|
||||
.justifyContent(FlexAlign.SpaceBetween)
|
||||
}
|
||||
.width('100%')
|
||||
}
|
||||
.height('100%')
|
||||
.width('100%')
|
||||
.backgroundColor($r('app.color.background_shallow_grey'))
|
||||
}
|
||||
}
|
@ -0,0 +1,102 @@
|
||||
/*
|
||||
* Copyright (c) 2024 Shenzhen Kaihong Digital Industry Development Co., Ltd.
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import router from '@ohos.router';
|
||||
import image from '@ohos.multimedia.image';
|
||||
import Logger from '../../../util/Logger';
|
||||
import testNapi, { testNapiValue } from 'libentry.so';
|
||||
import { TitleBar } from '../../../common/TitleBar'
|
||||
import hilog from '@ohos.hilog';
|
||||
|
||||
const TAG: string = 'napi_unwrap';
|
||||
|
||||
@Entry
|
||||
@Component
|
||||
struct napiunwrap {
|
||||
private btnFontColor: Resource = $r('app.color.white');
|
||||
private pixelMapFormat: image.PixelMapFormat = 3;
|
||||
@State isSetInstance: Boolean = false;
|
||||
@State imagePixelMap: PixelMap | undefined = undefined;
|
||||
@State textcont: string = 'napi_unwrap解除封装在 JavaScript 对象中的原生实例。';
|
||||
@State testcont: string = ' // 测试 N-API napi_unwrap \n'
|
||||
+ ' const result = testNapi.testNapiUnwrap(true); \n'
|
||||
+ ' console.log(result); \n'
|
||||
|
||||
|
||||
controller: TextAreaController = new TextAreaController()
|
||||
|
||||
build() {
|
||||
Column() {
|
||||
// 标题
|
||||
TitleBar({ title: $r('app.string.napi_unwrap') })
|
||||
|
||||
Column() {
|
||||
Column() {
|
||||
TextArea({
|
||||
text: this.textcont,
|
||||
placeholder: '',
|
||||
})
|
||||
.placeholderFont({ size: 16, weight: 400 })
|
||||
.width('90%')
|
||||
.margin(10)
|
||||
.fontSize(16)
|
||||
.fontColor($r('app.color.sub_title_color'))
|
||||
.backgroundColor($r('app.color.white'))
|
||||
.enabled(false)
|
||||
|
||||
TextArea({
|
||||
text: this.testcont,
|
||||
placeholder: '',
|
||||
})
|
||||
.placeholderFont({ size: 16, weight: 400 })
|
||||
.width('90%')
|
||||
.margin(10)
|
||||
.fontSize(16)
|
||||
.fontColor($r('app.color.textarea_font_color'))
|
||||
.backgroundColor($r('app.color.white'))
|
||||
.enabled(false)
|
||||
}
|
||||
.width('100%')
|
||||
.alignItems(HorizontalAlign.Center)
|
||||
.justifyContent(FlexAlign.Start)
|
||||
|
||||
Row() {
|
||||
Button($r('app.string.napi_unwrap'), { type: ButtonType.Capsule })
|
||||
.backgroundColor(Color.Blue)
|
||||
.width('80%')
|
||||
.height(48)
|
||||
.fontSize(16)
|
||||
.fontWeight(500)
|
||||
.fontColor(this.btnFontColor)
|
||||
.margin({ left: 24 })
|
||||
.id('napi_unwrap')
|
||||
.onClick(() => {
|
||||
let ret1 = testNapi.testNapiUnwrap(true);
|
||||
console.log(`testNapi.testNapiUnwrap() is ${ret1}`);
|
||||
this.testcont = this.testcont.replace('log(result)', 'log(## ' + ret1 + ' ##)');
|
||||
})
|
||||
}
|
||||
.width('100%')
|
||||
.height(48)
|
||||
.alignItems(VerticalAlign.Center)
|
||||
.justifyContent(FlexAlign.SpaceBetween)
|
||||
}
|
||||
.width('100%')
|
||||
}
|
||||
.height('100%')
|
||||
.width('100%')
|
||||
.backgroundColor($r('app.color.background_shallow_grey'))
|
||||
}
|
||||
}
|
@ -0,0 +1,101 @@
|
||||
/*
|
||||
* Copyright (c) 2024 Shenzhen Kaihong Digital Industry Development Co., Ltd.
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import router from '@ohos.router';
|
||||
import image from '@ohos.multimedia.image';
|
||||
import Logger from '../../../util/Logger';
|
||||
import testNapi, { testNapiValue } from 'libentry.so';
|
||||
import { TitleBar } from '../../../common/TitleBar'
|
||||
import hilog from '@ohos.hilog';
|
||||
|
||||
const TAG: string = 'napi_wrap';
|
||||
|
||||
@Entry
|
||||
@Component
|
||||
struct napiwrap {
|
||||
private btnFontColor: Resource = $r('app.color.white');
|
||||
private pixelMapFormat: image.PixelMapFormat = 3;
|
||||
@State isSetInstance: Boolean = false;
|
||||
@State imagePixelMap: PixelMap | undefined = undefined;
|
||||
@State textcont: string = 'napi_wrap在 JavaScript 对象中封装原生实例。';
|
||||
@State testcont: string = ' // 测试 N-API napi_wrap \n'
|
||||
+ ' const result = testNapi.testNapiWrap(); \n'
|
||||
+ ' console.log(result); \n'
|
||||
|
||||
|
||||
controller: TextAreaController = new TextAreaController()
|
||||
|
||||
build() {
|
||||
Column() {
|
||||
// 标题
|
||||
TitleBar({ title: $r('app.string.napi_wrap') })
|
||||
|
||||
Column() {
|
||||
Column() {
|
||||
TextArea({
|
||||
text: this.textcont,
|
||||
placeholder: '',
|
||||
})
|
||||
.placeholderFont({ size: 16, weight: 400 })
|
||||
.width('90%')
|
||||
.margin(10)
|
||||
.fontSize(16)
|
||||
.fontColor($r('app.color.sub_title_color'))
|
||||
.backgroundColor($r('app.color.white'))
|
||||
.enabled(false)
|
||||
|
||||
TextArea({
|
||||
text: this.testcont,
|
||||
placeholder: '',
|
||||
})
|
||||
.placeholderFont({ size: 16, weight: 400 })
|
||||
.width('90%')
|
||||
.margin(10)
|
||||
.fontSize(16)
|
||||
.fontColor($r('app.color.textarea_font_color'))
|
||||
.backgroundColor($r('app.color.white'))
|
||||
.enabled(false)
|
||||
}
|
||||
.width('100%')
|
||||
.alignItems(HorizontalAlign.Center)
|
||||
.justifyContent(FlexAlign.Start)
|
||||
|
||||
Row() {
|
||||
Button($r('app.string.napi_wrap'), { type: ButtonType.Capsule })
|
||||
.backgroundColor(Color.Blue)
|
||||
.width('80%')
|
||||
.height(48)
|
||||
.fontSize(16)
|
||||
.fontWeight(500)
|
||||
.fontColor(this.btnFontColor)
|
||||
.margin({ left: 24 })
|
||||
.id('napi_wrap')
|
||||
.onClick(() => {
|
||||
console.log(`testNapi.testNapiWrap() is ${testNapi.testNapiWrap('tree')}`);
|
||||
this.testcont = this.testcont.replace('log(result)', 'log(## ' +typeof (testNapi.testNapiWrap('tree')) + ' ##)');
|
||||
})
|
||||
}
|
||||
.width('100%')
|
||||
.height(48)
|
||||
.alignItems(VerticalAlign.Center)
|
||||
.justifyContent(FlexAlign.SpaceBetween)
|
||||
}
|
||||
.width('100%')
|
||||
}
|
||||
.height('100%')
|
||||
.width('100%')
|
||||
.backgroundColor($r('app.color.background_shallow_grey'))
|
||||
}
|
||||
}
|
@ -98,6 +98,10 @@
|
||||
"pages/javascript/jsabstractops/napistrictequals",
|
||||
"pages/javascript/jsvalues/napicreateint32",
|
||||
"pages/javascript/jsvalues/napicreateuint32",
|
||||
"pages/javascript/jsvalues/napicreateint64"
|
||||
"pages/javascript/jsvalues/napicreateint64",
|
||||
"pages/javascript/jsfunctions/napicallfunction",
|
||||
"pages/javascript/jsfunctions/napicreatefunction",
|
||||
"pages/javascript/jsobjectwrap/napiwrap",
|
||||
"pages/javascript/jsobjectwrap/napiunwrap"
|
||||
]
|
||||
}
|
||||
|
@ -0,0 +1,71 @@
|
||||
/*
|
||||
* Copyright (c) 2024 Shenzhen Kaihong Digital Industry Development Co., Ltd.
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import hilog from '@ohos.hilog';
|
||||
import testNapi, { add } from 'libentry.so';
|
||||
import { describe, beforeAll, beforeEach, afterEach, afterAll, it, expect } from '@ohos/hypium';
|
||||
|
||||
function AddTwo(num: number) {
|
||||
return num + 2;
|
||||
}
|
||||
|
||||
export default function abilityTestJsFunctions() {
|
||||
describe('ActsAbilityTestJsFunctions', () => {
|
||||
// Defines a test suite. Two parameters are supported: test suite name and test suite function.
|
||||
beforeAll(() => {
|
||||
// Presets an action, which is performed only once before all test cases of the test suite start.
|
||||
// This API supports only one parameter: preset action function.
|
||||
})
|
||||
beforeEach(() => {
|
||||
// Presets an action, which is performed before each unit test case starts.
|
||||
// The number of execution times is the same as the number of test cases defined by **it**.
|
||||
// This API supports only one parameter: preset action function.
|
||||
})
|
||||
afterEach(() => {
|
||||
// Presets a clear action, which is performed after each unit test case ends.
|
||||
// The number of execution times is the same as the number of test cases defined by **it**.
|
||||
// This API supports only one parameter: clear action function.
|
||||
})
|
||||
afterAll(() => {
|
||||
// Presets a clear action, which is performed after all test cases of the test suite end.
|
||||
// This API supports only one parameter: clear action function.
|
||||
})
|
||||
|
||||
it('testNapiCallFunction', 0, () => {
|
||||
// Defines a test case. This API supports three parameters: test case name, filter parameter, and test case function.
|
||||
hilog.info(0x0000, 'testTag', '%{public}s', 'it testNapiCallFunction begin');
|
||||
let result = testNapi.testNapiCallFunction(AddTwo, 7);
|
||||
hilog.info(0x0000, 'testTag', `napi_call_function(AddTwo, 7) = ${result}`);
|
||||
expect(result).assertEqual(9);
|
||||
|
||||
let result1 = testNapi.testNapiCallFunction(AddTwo, 888);
|
||||
hilog.info(0x0000, 'testTag', `napi_call_function(AddTwo, 888) = ${result1}`);
|
||||
expect(result1).assertEqual(890);
|
||||
|
||||
let result2 = testNapi.testNapiCallFunction(AddTwo, 77);
|
||||
hilog.info(0x0000, 'testTag', `napi_call_function(AddTwo, 77) = ${result2}`);
|
||||
expect(result2).assertEqual(79);
|
||||
})
|
||||
|
||||
it('testNapiCreateFunction', 0, () => {
|
||||
// Defines a test case. This API supports three parameters: test case name, filter parameter, and test case function.
|
||||
hilog.info(0x0000, 'testTag', '%{public}s', 'it testNapiCreateFunction begin');
|
||||
// let result = testNapi.testNapiCreateFunction();
|
||||
hilog.info(0x0000, 'testTag', `type of napi_create_functon() is ${typeof(testNapi.testNapiCreateFunction())}`);
|
||||
expect(typeof(testNapi.testNapiCreateFunction())).assertEqual('function');
|
||||
})
|
||||
|
||||
})
|
||||
}
|
@ -0,0 +1,73 @@
|
||||
/*
|
||||
* Copyright (c) 2024 Shenzhen Kaihong Digital Industry Development Co., Ltd.
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import hilog from '@ohos.hilog';
|
||||
import testNapi from 'libentry.so';
|
||||
import { describe, beforeAll, beforeEach, afterEach, afterAll, it, expect } from '@ohos/hypium';
|
||||
|
||||
export default function abilityTestJsObjectWrap() {
|
||||
describe('ActsAbilityTestJsObjectWrap', () => {
|
||||
// Defines a test suite. Two parameters are supported: test suite name and test suite function.
|
||||
beforeAll(() => {
|
||||
// Presets an action, which is performed only once before all test cases of the test suite start.
|
||||
// This API supports only one parameter: preset action function.
|
||||
})
|
||||
beforeEach(() => {
|
||||
// Presets an action, which is performed before each unit test case starts.
|
||||
// The number of execution times is the same as the number of test cases defined by **it**.
|
||||
// This API supports only one parameter: preset action function.
|
||||
})
|
||||
afterEach(() => {
|
||||
// Presets a clear action, which is performed after each unit test case ends.
|
||||
// The number of execution times is the same as the number of test cases defined by **it**.
|
||||
// This API supports only one parameter: clear action function.
|
||||
})
|
||||
afterAll(() => {
|
||||
// Presets a clear action, which is performed after all test cases of the test suite end.
|
||||
// This API supports only one parameter: clear action function.
|
||||
})
|
||||
|
||||
it('testNapiWrap', 0, () => {
|
||||
// Defines a test case. This API supports three parameters: test case name, filter parameter, and test case function.
|
||||
hilog.info(0x0000, 'testTag', '%{public}s', 'it testNapiWrap begin');
|
||||
hilog.info(0x0000, 'testTag', `type of napi_wrap("7") is = ${typeof (testNapi.testNapiWrap("7"))}`);
|
||||
expect(typeof (testNapi.testNapiWrap("7"))).assertEqual('object');
|
||||
|
||||
hilog.info(0x0000, 'testTag', `type of napi_wrap("tree") is = ${typeof (testNapi.testNapiWrap("tree"))}`);
|
||||
expect(typeof (testNapi.testNapiWrap("tree"))).assertEqual('object');
|
||||
})
|
||||
|
||||
it('testNapiUnwrap', 0, () => {
|
||||
// Defines a test case. This API supports three parameters: test case name, filter parameter, and test case function.
|
||||
hilog.info(0x0000, 'testTag', '%{public}s', 'it testNapiUnwrap begin');
|
||||
let ret = testNapi.testNapiUnwrap(7);
|
||||
hilog.info(0x0000, 'testTag', `type of napi_unwrap(7) is = ${ret}`);
|
||||
expect(ret).assertEqual('number');
|
||||
|
||||
let ret1 = testNapi.testNapiUnwrap('tree');
|
||||
hilog.info(0x0000, 'testTag', `type of napi_unwrap('tree') is = ${ret1}`);
|
||||
expect(ret1).assertEqual('string');
|
||||
|
||||
let ret2 = testNapi.testNapiUnwrap(false);
|
||||
hilog.info(0x0000, 'testTag', `type of napi_unwrap(false) is = ${ret2}`);
|
||||
expect(ret2).assertEqual('boolean');
|
||||
|
||||
let ret3 = testNapi.testNapiUnwrap(null);
|
||||
hilog.info(0x0000, 'testTag', `type of napi_unwrap(null) is = ${ret3}`);
|
||||
expect(ret3).assertEqual('null');
|
||||
})
|
||||
|
||||
})
|
||||
}
|
@ -16,6 +16,7 @@
|
||||
"onCommand:extension.h2dts",
|
||||
"onCommand:extension.h2dtscpp",
|
||||
"onCommand:extension.dts2cpp",
|
||||
"onCommand:extension.ohcrosscompile",
|
||||
"onCommand:extension.h2sa",
|
||||
"onCommand:extension.h2hdf"
|
||||
],
|
||||
@ -41,6 +42,11 @@
|
||||
{
|
||||
"command": "extension.h2hdf",
|
||||
"title": "%extension.h2hdf.title%"
|
||||
|
||||
},
|
||||
{
|
||||
"command": "extension.ohcrosscompile",
|
||||
"title": "OH_CrossCompile"
|
||||
}
|
||||
],
|
||||
"submenus": [
|
||||
@ -82,6 +88,11 @@
|
||||
"submenu": "gen-menulist",
|
||||
"when": "resourceExtname == .h || resourceExtname == .ts",
|
||||
"group": "2_workspace"
|
||||
},
|
||||
{
|
||||
"command": "extension.ohcrosscompile",
|
||||
"when": "resourceScheme == 'file'",
|
||||
"group": "2_workspace"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
@ -13,6 +13,8 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import internal = require("stream");
|
||||
|
||||
export interface FileTemp {
|
||||
name: string;
|
||||
content: string;
|
||||
@ -27,6 +29,33 @@ export interface DirTemp {
|
||||
export interface ParamObj {
|
||||
type: string;
|
||||
name: string;
|
||||
arraySize: number;
|
||||
}
|
||||
|
||||
export interface EnumObj {
|
||||
name: string;
|
||||
alias: string;
|
||||
members: string[];
|
||||
}
|
||||
|
||||
export interface UnionObj {
|
||||
name: string;
|
||||
alias: string;
|
||||
members: ParamObj[];
|
||||
}
|
||||
|
||||
export interface StructObj {
|
||||
name: string;
|
||||
alias: string;
|
||||
members: ParamObj[];
|
||||
functions: FuncObj[];
|
||||
}
|
||||
|
||||
export interface ClassObj {
|
||||
name: string;
|
||||
alias: string;
|
||||
variableList: ParamObj[];
|
||||
functionList: FuncObj[];
|
||||
}
|
||||
|
||||
export interface FuncObj {
|
||||
@ -36,6 +65,10 @@ export interface FuncObj {
|
||||
}
|
||||
|
||||
export interface ParseObj {
|
||||
enums: EnumObj[];
|
||||
unions: UnionObj[];
|
||||
structs: StructObj[];
|
||||
classes: ClassObj[];
|
||||
funcs: FuncObj[];
|
||||
}
|
||||
|
||||
|
@ -33,6 +33,22 @@ export function activate(context: vscode.ExtensionContext) {
|
||||
// This line of code will only be executed once when your extension is activated
|
||||
console.log('Congratulations, your extension "helloworld-sample" is now active!');
|
||||
|
||||
const ohcrosscompile = vscode.commands.registerCommand('extension.ohcrosscompile', async (uri) => {
|
||||
// The code you place here will be executed every time your command is executed
|
||||
if (uri && uri.fsPath) {
|
||||
const stat = await vscode.workspace.fs.stat(uri);
|
||||
if (stat.type === vscode.FileType.Directory) {
|
||||
vscode.window.showInformationMessage(`You selected a directory: ${uri.fsPath}`);
|
||||
} else {
|
||||
vscode.window.showWarningMessage('Please select a directory.');
|
||||
}
|
||||
} else {
|
||||
vscode.window.showWarningMessage('No resource selected.');
|
||||
}
|
||||
// Display a message box to the user
|
||||
vscode.window.showInformationMessage('ohcrosscompile!');
|
||||
});
|
||||
|
||||
// The command has been defined in the package.json file
|
||||
// Now provide the implementation of the command with registerCommand
|
||||
// The commandId parameter must match the command field in package.json
|
||||
|
@ -138,7 +138,8 @@ function getInterFuncParams(str: string, paramObj: ParamObj[]) {
|
||||
let paramsStr = '';
|
||||
let paramObject: ParamObj = {
|
||||
name: '',
|
||||
type: ''
|
||||
type: '',
|
||||
arraySize: 0
|
||||
}
|
||||
let paramArr = replaceAll(str, '*', '').split(',');
|
||||
for (let i = 0; i < paramArr.length; i++) {
|
||||
@ -268,7 +269,8 @@ export function genDtsInterface(path: string, typeList: TypeList[], interfaceLis
|
||||
interDefine += variableDefine;
|
||||
let paramObj: ParamObj = {
|
||||
name: variableName,
|
||||
type: replaceAll(variabletype, 'struct', '').trim()
|
||||
type: replaceAll(variabletype, 'struct', '').trim(),
|
||||
arraySize: 0
|
||||
}
|
||||
paramsContent.push(paramObj);
|
||||
}
|
||||
@ -322,11 +324,13 @@ function createParam(parseParamInfo: ParamObj) {
|
||||
let tsParam: ParamObj = {
|
||||
name: '',
|
||||
type: '',
|
||||
arraySize: 0
|
||||
};
|
||||
|
||||
let cppParam: ParamObj = {
|
||||
name: '',
|
||||
type: '',
|
||||
arraySize: 0
|
||||
};
|
||||
tsParam.name = replaceAll(parseParamInfo.name, '*', '');
|
||||
cppParam.name = tsParam.name;
|
||||
|
@ -16,13 +16,272 @@
|
||||
import * as vscode from 'vscode';
|
||||
import * as path from 'path';
|
||||
import * as ts from 'typescript';
|
||||
import { ParamObj, FuncObj, ParseObj } from './datatype'
|
||||
import { ParamObj, FuncObj, StructObj, ClassObj, EnumObj, UnionObj, ParseObj } from './datatype'
|
||||
|
||||
import fs = require('fs');
|
||||
|
||||
function parseEnum(data: string) {
|
||||
// 使用正则表达式提取枚举定义
|
||||
const enumRegex = /typedef\s+enum\s+(\w*)\s*{([^}]*)}\s*(\w+);|enum\s+(\w+)\s*{([^}]*)}\s*;/g;
|
||||
const enums: EnumObj[] = [];
|
||||
let match;
|
||||
while ((match = enumRegex.exec(data)) !== null) {
|
||||
const enumName = match[1] ||match[3] || match[4];
|
||||
const aliasName = match[3];
|
||||
const membersString = match[2] || match[5];
|
||||
const members = membersString.split(';')
|
||||
.map(member => member.trim().replace(/[\n\r\s]/g, ''))
|
||||
.filter(member => member.length > 0);
|
||||
let enumItem = {
|
||||
"name": enumName,
|
||||
"alias": aliasName,
|
||||
"members": members
|
||||
}
|
||||
enums.push(enumItem);
|
||||
}
|
||||
console.info(` return enums: ${JSON.stringify(enums)}`);
|
||||
return enums;
|
||||
}
|
||||
|
||||
function parseUnion(data: string) {
|
||||
// 使用正则表达式提取联合体定义
|
||||
const unionRegex = /typedef\s+struct\s*(\w*)\s*{([^}]*)}\s*(\w+)\s*;|union\s+(\w+)\s*{([^}]*)}\s*;/g;
|
||||
const unions: UnionObj[] = [];
|
||||
let match;
|
||||
while ((match = unionRegex.exec(data)) !== null) {
|
||||
const unionName = match[1] || match[3] || match[4]; // 获取结构体名字
|
||||
const aliasName = match[3];
|
||||
const membersString = match[2] || match[5]; // 获取成员声明
|
||||
const members = membersString.split(';')
|
||||
.map(member => member.trim().replace(/[\n\r]/g, ''))
|
||||
.filter(member => member.length > 0);
|
||||
|
||||
let unionItem: UnionObj = {
|
||||
"name": unionName,
|
||||
"alias": aliasName,
|
||||
"members": []
|
||||
}
|
||||
|
||||
members.forEach(declaration => {
|
||||
// 使用正则表达式匹配类型和变量名
|
||||
const match = declaration.match(/(\w+)\s+(\w+)(\[(\d+)\])?/);
|
||||
if (match) {
|
||||
const type = match[1]; // 类型
|
||||
const variable = match[2]; // 变量名
|
||||
const arrayLength = match[4] ? parseInt(match[4], 10) : -1; // 解析数组长度
|
||||
// console.log(`Type: ${type}, Variable:${variable}, Size:${arrayLength}`);
|
||||
let paramItem: ParamObj = {
|
||||
"type": type,
|
||||
"name": variable,
|
||||
"arraySize": arrayLength
|
||||
}
|
||||
unionItem.members.push(paramItem);
|
||||
}
|
||||
});
|
||||
|
||||
unions.push(unionItem);
|
||||
}
|
||||
console.info(` return unions: ${JSON.stringify(unions)}`);
|
||||
return unions;
|
||||
}
|
||||
|
||||
function parseStruct(data: string) {
|
||||
// 使用正则表达式提取结构体定义
|
||||
// const structRegex = /typedef\s+struct\s+(\w+)\s*{([^}]*)}\s*(\w+);/g;
|
||||
// const structRegex = /(\btypedef\b\s+)?struct\s+\w*\s*{([^}]*)}\s*(\w+);/g;
|
||||
const structRegex = /typedef\s+struct\s*(\w*)\s*{([^}]*)}\s*(\w+)\s*;|struct\s+(\w+)\s*{([^}]*)}\s*;/g;
|
||||
// const structs: Record<string, string[]> = {};
|
||||
const structs: StructObj[] = [];
|
||||
let match;
|
||||
while ((match = structRegex.exec(data)) !== null) {
|
||||
const structName = match[1] ||match[3] || match[4]; // 获取结构体名字
|
||||
const alias = match[3];
|
||||
const membersString = match[2] || match[5]; // 获取成员声明
|
||||
|
||||
const members = membersString.split(';')
|
||||
.map(member => member.trim().replace(/[\n\r]/g, ''))
|
||||
.filter(member => member.length > 0);
|
||||
|
||||
let structItem: StructObj = {
|
||||
"name": structName,
|
||||
"alias": alias,
|
||||
"members": parseMembers(members),
|
||||
"functions": []
|
||||
}
|
||||
|
||||
structs.push(structItem);
|
||||
}
|
||||
console.info(` return structs: ${JSON.stringify(structs)}`);
|
||||
return structs;
|
||||
}
|
||||
|
||||
function parseMembers(members: string[]): ParamObj[] {
|
||||
const memberRegex = /(?:public:|private:)?\s*(\w+(?:\s+\w+)?)\s+(\w+)(?:\[(\d+)\])?/;
|
||||
|
||||
return members.map(member => {
|
||||
const match = member.trim().match(memberRegex);
|
||||
if (match) {
|
||||
const type = match[1];
|
||||
const name = match[2];
|
||||
const arraySize = match[3] ? parseInt(match[3], 10) : -1;
|
||||
return { type, name, arraySize };
|
||||
}
|
||||
return {};
|
||||
}).filter((m): m is ParamObj => m !== null); // 类型保护
|
||||
}
|
||||
|
||||
function parseFunctions(functions: string[]): FuncObj[] {
|
||||
const functionRegex = /(\w+)\s+(\w+)\(([^)]*)\)/; // 正则表达式匹配返回值、函数名和参数
|
||||
|
||||
return functions.map(func => {
|
||||
const match = func.trim().match(functionRegex);
|
||||
if (match) {
|
||||
const returns = match[1]; // 返回值类型
|
||||
const name = match[2]; // 方法名
|
||||
const parameterstr = match[3].split(',').map(param => param.trim()).filter(Boolean); // 分割参数并去除空值
|
||||
const parameters = parseMembers(parameterstr);
|
||||
return { returns, name, parameters };
|
||||
}
|
||||
return {};
|
||||
}).filter((f): f is FuncObj => f !== null); // 类型保护
|
||||
}
|
||||
|
||||
function parseClass(data: string) {
|
||||
// 使用正则表达式提取类定义
|
||||
const classRegex = /class\s+(\w+)\s*{([^}]*)}/g;
|
||||
const classes: ClassObj[] = []
|
||||
let match;
|
||||
while ((match = classRegex.exec(data)) !== null) {
|
||||
const className = match[1];
|
||||
const classMembers = match[2]
|
||||
.split(';')
|
||||
.map(member => member.trim().replace(/[\n\r]/g, ''))
|
||||
.filter(member => member.length > 0);
|
||||
|
||||
const variables: string[] = [];
|
||||
const methods: string[] = [];
|
||||
|
||||
classMembers.forEach(member => {
|
||||
// 匹配方法声明
|
||||
const methodRegex = /(\w[\w\s\*]+)\s+(\w+)\(([^)]*)\)\s*/;
|
||||
const variableRegex = /(\w[\w\s\*]+)\s+(\w+)\s*/;
|
||||
|
||||
if (methodRegex.test(member)) {
|
||||
methods.push(member.trim().replace(/[\n\r]/g, ''));
|
||||
} else if (variableRegex.test(member)) {
|
||||
variables.push(member.trim().replace(/[\n\r]/g, ''));
|
||||
}
|
||||
});
|
||||
|
||||
const variableList = parseMembers(variables);
|
||||
// console.log(`parseMembers: ${JSON.stringify(variableList)}`)
|
||||
|
||||
const functionList: FuncObj[] = parseFunctions(methods);
|
||||
// console.log(`parsedFunctions: ${JSON.stringify(functionList)}`);
|
||||
|
||||
const classItem: ClassObj = {
|
||||
"name": className,
|
||||
"alias": '',
|
||||
"variableList": variableList,
|
||||
"functionList": functionList
|
||||
}
|
||||
classes.push(classItem);
|
||||
}
|
||||
console.info(` return classes: ${JSON.stringify(classes)}`);
|
||||
return classes;
|
||||
}
|
||||
|
||||
function parseFunction(data: string) {
|
||||
// 使用正则表达式提取函数定义
|
||||
const functionRegex1 = /([a-zA-Z_]\w*\s+)+([*a-zA-Z_]\w+)\s*\(([^)]*)\)\s*(?={|;)/g;
|
||||
const functionRegex2 = /(\w+\s*\(.*?\)\s+)(\w+)\s*\((.*?)\);\s*/g;
|
||||
|
||||
let functions = data.match(functionRegex1) || [];
|
||||
if (functions.length <= 0) {
|
||||
console.info("use functionRegex2");
|
||||
functions = data.match(functionRegex2) || [];
|
||||
}
|
||||
const functionDetails: FuncObj[] = functions.map(func => {
|
||||
// 函数解析逻辑...
|
||||
// 普通类型的函数识别
|
||||
if (func.trim().startsWith('typedef')) {
|
||||
func = func.replace('typedef', '');
|
||||
}
|
||||
let parts = func.trim().match(/([a-zA-Z_]\w+)\s+\(*([*a-zA-Z_]\w+)\)*\s*\(([^)]*)\)/);
|
||||
if (!parts) {
|
||||
console.info("use regex2");
|
||||
parts = func.trim().match(/(\w+\s*\(.*?\)\s+)(\w+)\s*\((.*?)\);\s*/);
|
||||
}
|
||||
if (parts) {
|
||||
let index = 1;
|
||||
let returnType = parts[index].trim();
|
||||
let functionName = parts[index + 1].trim();
|
||||
let paramList = parts[index + 2].split(',');
|
||||
if (parts[index].trim() === 'typedef') {
|
||||
console.info("typedef -------------", parts);
|
||||
returnType = parts[index + 1].trim();
|
||||
functionName = parts[index + 2].trim();
|
||||
paramList = parts[index + 3].split(',');
|
||||
}
|
||||
|
||||
let paramResList = [];
|
||||
for (let i=0; i<paramList.length; i++) {
|
||||
let paramItem = paramList[i].trim();
|
||||
|
||||
let lastTabIndex = paramItem.lastIndexOf(' ');
|
||||
let paramType = paramItem.substring(0, lastTabIndex).trim();
|
||||
let paramName = paramItem.substring(lastTabIndex, paramItem.length).trim();
|
||||
paramResList.push({
|
||||
name: paramName,
|
||||
type: paramType,
|
||||
arraySize: 0,
|
||||
})
|
||||
}
|
||||
console.info(`ret: ${returnType} func: ${functionName} params:(${paramResList.map(ditem => {
|
||||
return ' type: ' + ditem.type + ', ' + 'name: ' + ditem.name;
|
||||
})})`)
|
||||
let funcRes: FuncObj = {
|
||||
name: functionName,
|
||||
returns: returnType,
|
||||
parameters: paramResList
|
||||
}
|
||||
return funcRes;
|
||||
}
|
||||
let res: FuncObj = {
|
||||
name: '',
|
||||
returns: '',
|
||||
parameters: []
|
||||
}
|
||||
return res;
|
||||
})
|
||||
.filter(detail => detail !== null);
|
||||
|
||||
return functionDetails;
|
||||
// if (functionDetails.length > 0) {
|
||||
// const funcs = [...functionDetails.filter((funcItem) : funcItem is FuncObj => funcItem !== null)];
|
||||
// const message = functionDetails.map(detail =>
|
||||
// `Function: ${detail!.name},
|
||||
// Return Type: ${detail!.returns},
|
||||
// Parameters: (${detail!.parameters.map(ditem => {
|
||||
// return ' type: ' + ditem.type + ', ' + 'name: ' + ditem.name;
|
||||
// })})`
|
||||
// ).join('\n');
|
||||
// console.info(` return parseFunctions: ${JSON.stringify(funcs)}`);
|
||||
// return funcs;
|
||||
// } else {
|
||||
// vscode.window.showInformationMessage('No functions found.');
|
||||
// }
|
||||
}
|
||||
|
||||
export function parseHeaderFile(filePath: string): Promise<ParseObj> {
|
||||
return new Promise((resolve, reject) => {
|
||||
let parseRes: ParseObj = { funcs: [] };
|
||||
let parseRes: ParseObj = {
|
||||
enums: [],
|
||||
unions: [],
|
||||
structs: [],
|
||||
classes: [],
|
||||
funcs: []
|
||||
};
|
||||
|
||||
// 读取文件内容
|
||||
fs.readFile(filePath, 'utf8', (err: NodeJS.ErrnoException | null, data: string) => {
|
||||
@ -31,79 +290,21 @@ export function parseHeaderFile(filePath: string): Promise<ParseObj> {
|
||||
reject(err);
|
||||
return;
|
||||
}
|
||||
// 使用正则表达式提取函数定义
|
||||
const functionRegex1 = /([a-zA-Z_]\w*\s+)+([*a-zA-Z_]\w+)\s*\(([^)]*)\)\s*(?={|;)/g;
|
||||
const functionRegex2 = /(\w+\s*\(.*?\)\s+)(\w+)\s*\((.*?)\);\s*/g;
|
||||
|
||||
let functions = data.match(functionRegex1) || [];
|
||||
if (functions.length <= 0) {
|
||||
console.info("use functionRegex2");
|
||||
functions = data.match(functionRegex2) || [];
|
||||
}
|
||||
const functionDetails: (FuncObj | null)[] = functions.map(func => {
|
||||
// 函数解析逻辑...
|
||||
// 普通类型的函数识别
|
||||
if (func.trim().startsWith('typedef')) {
|
||||
func = func.replace('typedef', '');
|
||||
}
|
||||
let parts = func.trim().match(/([a-zA-Z_]\w+)\s+\(*([*a-zA-Z_]\w+)\)*\s*\(([^)]*)\)/);
|
||||
if (!parts) {
|
||||
console.info("use regex2");
|
||||
parts = func.trim().match(/(\w+\s*\(.*?\)\s+)(\w+)\s*\((.*?)\);\s*/);
|
||||
}
|
||||
if (parts) {
|
||||
let index = 1;
|
||||
let returnType = parts[index].trim();
|
||||
let functionName = parts[index + 1].trim();
|
||||
let paramList = parts[index + 2].split(',');
|
||||
if (parts[index].trim() === 'typedef') {
|
||||
console.info("typedef -------------", parts);
|
||||
returnType = parts[index + 1].trim();
|
||||
functionName = parts[index + 2].trim();
|
||||
paramList = parts[index + 3].split(',');
|
||||
}
|
||||
|
||||
let paramResList = [];
|
||||
for (let i=0; i<paramList.length; i++) {
|
||||
let paramItem = paramList[i].trim();
|
||||
|
||||
let lastTabIndex = paramItem.lastIndexOf(' ');
|
||||
let paramType = paramItem.substring(0, lastTabIndex).trim();
|
||||
let paramName = paramItem.substring(lastTabIndex, paramItem.length).trim();
|
||||
paramResList.push({
|
||||
name: paramName,
|
||||
type: paramType,
|
||||
})
|
||||
}
|
||||
console.info(`ret: ${returnType} func: ${functionName} params:(${paramResList.map(ditem => {
|
||||
return ' type: ' + ditem.type + ', ' + 'name: ' + ditem.name;
|
||||
})})`)
|
||||
let funcRes: FuncObj = {
|
||||
name: functionName,
|
||||
returns: returnType,
|
||||
parameters: paramResList
|
||||
}
|
||||
return funcRes;
|
||||
}
|
||||
return null;
|
||||
})
|
||||
.filter(detail => detail !== null);
|
||||
|
||||
if (functionDetails.length > 0) {
|
||||
parseRes.funcs = [...functionDetails.filter((funcItem) : funcItem is FuncObj => funcItem !== null)];
|
||||
const message = functionDetails.map(detail =>
|
||||
`Function: ${detail!.name},
|
||||
Return Type: ${detail!.returns},
|
||||
Parameters: (${detail!.parameters.map(ditem => {
|
||||
return ' type: ' + ditem.type + ', ' + 'name: ' + ditem.name;
|
||||
})})`
|
||||
).join('\n');
|
||||
console.info(` return parseRes: ${JSON.stringify(parseRes)}`);
|
||||
vscode.window.showInformationMessage(message);
|
||||
resolve(parseRes);
|
||||
} else {
|
||||
vscode.window.showInformationMessage('No functions found.');
|
||||
const enumList = parseEnum(data);
|
||||
const unionList = parseUnion(data);
|
||||
const structList = parseStruct(data);
|
||||
const classList = parseClass(data);
|
||||
const funcList = parseFunction(data);
|
||||
parseRes = {
|
||||
enums: enumList,
|
||||
unions: unionList,
|
||||
structs: structList,
|
||||
classes: classList,
|
||||
funcs: funcList
|
||||
}
|
||||
console.info(` return parse result: ${JSON.stringify(parseRes)}`);
|
||||
resolve(parseRes);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user