Skip to content

Commit

Permalink
feat(ohos): update jsi doc && fix null pointer
Browse files Browse the repository at this point in the history
  • Loading branch information
zealotchen0 committed Dec 12, 2024
1 parent 2915362 commit 1c45519
Show file tree
Hide file tree
Showing 8 changed files with 198 additions and 4 deletions.
135 changes: 135 additions & 0 deletions docs/development/native-module.md
Original file line number Diff line number Diff line change
Expand Up @@ -260,6 +260,141 @@ HIPPY_EXPORT_METHOD(click) {
@end
```

# 鸿蒙

很多时候 `JS` 需要访问对应终端的一些能力模块,比如数据库、下载、网络请求等,这时候就需要使用 `Module` 来暴露接口给JS使用。Voltron SDK 中默认实现了部分 `Module`,但这极有可能无法满足你的需求,这就需要你对 `Module` 进行扩展封装。

---

## Module扩展

我们将以 `TestModule` 为例,从头扩展一个 `Module`,这个 `Module` 将展示前端如何调用终端能力,并且把结果返回给前端

终端扩展 `Module` 包括四步:

1. 创建 `TestModule`
2. 实现导出给 `JS` 的方法。
3. 注册 `Module`。

## 1. 创建 `TestModule`,并且继承 HippyNativeModuleBase

```typescript
export class ExampleNativeModule extends HippyNativeModuleBase {
public static readonly NAME = 'ExampleNativeModule'

constructor(ctx: HippyEngineContext) {
super(ctx)
}

public call(method: string, params: Array<HippyAny>, promise: HippyModulePromise): HippyAny {
switch (method) {
case 'test': {
this.test();
break;
}
case 'testPromise': {
this.testPromise(params, promise);
break;
}
case 'testSendEvent': {
this.testSendEvent(params, promise);
}
default:
super.call(method, params, promise);
}
return null;
}

public test() {
LogUtils.i(ExampleNativeModule.NAME, 'module test');
}

public testPromise(params: Array<HippyAny>, promise: HippyModulePromise) {
promise.resolve('test');
}

public testSendEvent(params: Array<HippyAny>, promise: HippyModulePromise) {
LogUtils.i(ExampleNativeModule.NAME, 'testSendEvent');
if (this.ctx != null && this.ctx.getModuleManager() != null) {
const eventModule = this.ctx.getModuleManager().getJavaScriptModule(EventDispatcher.MODULE_NAME);
if (eventModule != null) {
const event = 'testEvent';
const params = new Map<string, HippyAny>();
params.set('testString', 'testStringValue');

const valueMap = new Map<string, HippyAny>();
valueMap.set('testString2', 'testStringValue2');
params.set('testMap', valueMap);

const array: HippyArray = [];
array.push(valueMap);
params.set('testArray', array);

(eventModule as EventDispatcher).receiveNativeEvent(event, params);
}
}
}

}

```

需要注意的是,这里与Android、iOS有几处不同。

1. 需要指定 NAME,设置为前端调用的 module name

2. 需要实现 call 方法

## Turbo Module扩展

Module 的扩展一致,不过还需要配置 isTurbo 方法,且不需要实现 call 方法,参考如下:

```typescript
export class ExampleNativeTurboModule extends HippyNativeModuleBase {
public static readonly NAME = 'demoTurbo'

constructor(ctx: HippyEngineContext) {
super(ctx)
}

isTurbo(): boolean {
return false
}

public getString(info: string): string {
return 'demoTurbo' + info;
}

public getNum(num: number): number {
return num;
}

public getBoolean(b: boolean): boolean {
return b;
}

public getMap(map: HippyMap): HippyMap {
return map
}

public getArray(array: HippyArray): HippyArray {
return array
}

public getObject(obj: HippyAny): HippyAny {
return obj
}

public getTurboConfig(): TurboConfig {
return new TurboConfig();
}

public printTurboConfig(turboConfig: TurboConfig): string {
return turboConfig.info;
}
}

```


# Voltron
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
#pragma once

#include <string>
#include <set>

#include "connector/turbo.h"
#include "driver/napi/js_ctx.h"
Expand Down Expand Up @@ -63,6 +64,7 @@ class ArkTsTurboModule {
std::shared_ptr<Turbo> impl;
napi_env env;
std::unique_ptr<hippy::napi::FunctionWrapper> wrapper_holder_;
std::set<std::string> method_set_;

std::shared_ptr<CtxValue> constructor;
std::unique_ptr<FunctionWrapper> constructor_wrapper;
Expand All @@ -74,6 +76,7 @@ class ArkTsTurboModule {
const std::shared_ptr<CtxValue>& prop_name,
hippy::napi::CallbackInfo& info,
void* data);
void InitMethodSet();

};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,19 +57,27 @@ std::shared_ptr<CtxValue> ArkTsTurboModule::InvokeArkTsMethod(const std::shared_
auto context = scope->GetContext();
string_view str_view;
std::string method;
std::shared_ptr<CtxValue> result;
std::shared_ptr<CtxValue> result = context->CreateUndefined();
if (context->GetValueString(prop_name, &str_view)) {
method = StringViewUtils::ToStdString(
StringViewUtils::ConvertEncoding(str_view, string_view::Encoding::Utf8).utf8_value());
}

FOOTSTONE_DLOG(INFO) << "invokeArkTSMethod, method = " << method.c_str();

auto method_set = method_set_;
OhNapiTaskRunner *taskRunner = OhNapiTaskRunner::Instance(env);
taskRunner->RunSyncTask([env = env, impl = impl, &info, context, method, &result]() {
taskRunner->RunSyncTask([env = env, impl = impl, &info, context, method, &result, &method_set]() {
ArkTS arkTs(env);
napi_ref turbo_module_ref = impl->GetRef();
auto turboModule = arkTs.GetObject(turbo_module_ref);
if (method_set.size() <= 0) {
FOOTSTONE_DLOG(ERROR) << "turboModule object has no method, method = " << method.c_str();
return;
}
if (method_set.find(method) == method_set.end()) {
FOOTSTONE_DLOG(ERROR) << "turboModule method is null, method = " << method.c_str();
return;
}
std::vector<napi_value> args;
for (size_t i = 0; i < info.Length(); ++i) {
auto item = info[i];
Expand All @@ -82,11 +90,34 @@ std::shared_ptr<CtxValue> ArkTsTurboModule::InvokeArkTsMethod(const std::shared_
return result;
}

void ArkTsTurboModule::InitMethodSet() {
ArkTS arkTs(env);
napi_ref turbo_module_ref = impl->GetRef();
auto turboModule = arkTs.GetObject(turbo_module_ref);
if (turboModule.isNull()) {
FOOTSTONE_DLOG(ERROR) << "turboModule object is null";
return;
}
std::vector<std::pair<napi_value, napi_value>> value = turboModule.GetKeyValuePairs();
if (value.size() <= 0) {
FOOTSTONE_DLOG(ERROR) << "turboModule object is null";
return;
}
std::vector<std::pair<napi_value, napi_value>> pairs = turboModule.GetObjectPrototypeProperties();
for (auto it = pairs.begin(); it != pairs.end(); it++) {
auto &pair = *it;
auto &pairItem1 = pair.first;
auto method = arkTs.GetString(pairItem1);
method_set_.insert(method);
}
}

ArkTsTurboModule::ArkTsTurboModule(const std::string& name,
std::shared_ptr<Turbo>& impl,
const std::shared_ptr<Ctx>& ctx,
napi_env env)
: name(name), impl(impl), env(env) {
InitMethodSet();
auto getter = std::make_unique<FunctionWrapper>([](CallbackInfo& info, void* data) {
auto scope_wrapper = reinterpret_cast<ScopeWrapper*>(std::any_cast<void*>(info.GetSlot()));
auto scope = scope_wrapper->scope.lock();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -150,11 +150,13 @@ export class HippyModuleManagerImpl implements HippyModuleManager {
if (creator) {
let module = creator(this.ctx)
if (module.isTurbo() !== isTurbo) {
LogUtils.e('hippy', name + ' module is not turbo module')
return null;
}
this.cachedNativeModuleMap.set(name, module)
return module
} else {
LogUtils.e('hippy', name + ' module is null')
return null
}
}
Expand Down
2 changes: 2 additions & 0 deletions modules/ohos/oh_napi/include/oh_napi/ark_ts.h
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,8 @@ class ArkTS {
uint32_t GetArrayLength(napi_value array);

std::vector<std::pair<napi_value, napi_value>> GetObjectProperties(napi_value object);

std::vector<std::pair<napi_value, napi_value>> GetObjectPrototypeProperties(napi_value object);

std::string GetString(napi_value value);

Expand Down
4 changes: 4 additions & 0 deletions modules/ohos/oh_napi/include/oh_napi/oh_napi_object.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,10 @@ class OhNapiObject {
napi_value GetProperty(napi_value key);

std::vector<std::pair<napi_value, napi_value>> GetKeyValuePairs();

std::vector<std::pair<napi_value, napi_value>> GetObjectPrototypeProperties();

bool isNull();

private:
ArkTS arkTs_;
Expand Down
8 changes: 8 additions & 0 deletions modules/ohos/oh_napi/src/ark_ts.cc
Original file line number Diff line number Diff line change
Expand Up @@ -254,6 +254,14 @@ uint32_t ArkTS::GetArrayLength(napi_value array) {
return length;
}

std::vector<std::pair<napi_value, napi_value>> ArkTS::GetObjectPrototypeProperties(napi_value object) {
napi_value prototype;
auto status = napi_get_prototype(env_, object, &prototype);
this->MaybeThrowFromStatus(status, "Failed to retrieve prototype object");
auto result = GetObjectProperties(prototype);
return result;
}

std::vector<std::pair<napi_value, napi_value>> ArkTS::GetObjectProperties(napi_value object) {
napi_value propertyNames;
auto status = napi_get_property_names(env_, object, &propertyNames);
Expand Down
11 changes: 10 additions & 1 deletion modules/ohos/oh_napi/src/oh_napi_object.cc
Original file line number Diff line number Diff line change
Expand Up @@ -35,4 +35,13 @@ napi_value OhNapiObject::GetProperty(napi_value key) {

std::vector<std::pair<napi_value, napi_value>> OhNapiObject::GetKeyValuePairs() {
return arkTs_.GetObjectProperties(object_);
}
}

std::vector<std::pair<napi_value, napi_value>> OhNapiObject::GetObjectPrototypeProperties() {
return arkTs_.GetObjectPrototypeProperties(object_);
}

bool OhNapiObject::isNull() {
auto type = arkTs_.GetType(object_);
return type == napi_undefined || type == napi_null;
}

0 comments on commit 1c45519

Please sign in to comment.