准备
这里只对 Android 侧进行了实现,iOS 侧因为没有实体机的原因,先放一放,原理都一样,代码也差不多。
官方在 Android 侧提供了一个抽象类BridgePlugin
,我们需要继承它实现一些方法来进行通信。在 ArkUI-X 侧同样提供了'@arkui-x.bridge
包来进行通信。
ArkUI-X 侧 Bridge
先看下ArkUI-X 侧提供的方案,官方文档在这里 @arkui-x.bridge.d.ts (平台桥接)。
在官方提供的场景示例中中,是在页面(也就是被@Entry
装饰的类)中创建的,但是在实践中发现不能正常运行,会创建 Bridge 对象时会报错
Error message: Cannot read property createBridge of undefined
指向了private bridgeImpl = bridge.createBridge('Bridge');
这一行代码,向官方提交了 issue,在其帮助下,将创建 Bridge 对象的代码放在了另外的 ets 文件中可以正常运行。
创建 Bridge
先导包 import Bridge from '@arkui-x.bridge';
再创建 bridgeObj: BridgeObject = Bridge.createBridge('Bridge');
需要注意的是,这里传入的参数值需要和 native 侧一致,否则无法调用。
Android 侧 BridgePlugin
看先 Android 侧提供的方案,官方文档在这里 BridgePlugin (平台桥接) 。
暴露的 api 也不多,包括构造方法、callMethod、sendMessage,两个回调监听:setMessageListener和setMethodResultListener。
创建 BridgePlugin
一般来讲,我们会自己写个类继承BridgePlugin
来进行操作
public class ArkUIBridge extends BridgePlugin{
private final String TAG = "ArkUIBridge";
public ArkUIBridge(Context context, String bridgeName, int instanceId) {
super(context, bridgeName, instanceId);
}
}
注意这里的bridgeName
参数,传入的值必须与 ArkUI-X 侧一致,至于 instanceId 则是StageActivity
这个用来展示 ArkUI-X 内容的容器提供的方法,其实也就是调用的InstanceIdGenerator.getAndIncrement()
,具体实现如下
package ohos.stage.ability.adapter;
import java.util.concurrent.atomic.AtomicInteger;
public final class InstanceIdGenerator {
private static final AtomicInteger ID_GENERATOR = new AtomicInteger(1);
public InstanceIdGenerator() {
}
public static int getAndIncrement() {
return ID_GENERATOR.getAndIncrement();
}
public static int get() {
return ID_GENERATOR.get();
}
}
我们可以在其他位置调用InstanceIdGenerator.get()
来获取到 id。但需要注意,每次创建 ArkUI-X 产物的容器页面也就是StageActivity时,该 id 都会自增,如果 id 无法对应则无法互相通信
ArkUI侧向Android侧传递数据
// xxx.ets
bridgeImpl.sendMessage('text').then((res)=>{
// 监听Android侧的回执
console.log('response: ' + res);
}).catch((err) => {
console.log('error: ' + JSON.stringify(err));
});
在 Android 侧接收消息,在构造方法里面设置一下监听事件
//ArkUIBridge extends BridgePlugin
public ArkUIBridge(Context context, String bridgeName, int instanceId) {
super(context, bridgeName, instanceId);
setMessageListener(new IMessageListener() {
@Override
public Object onMessage(Object o) {
Log.e(TAG,"onMessage-->" + o.toString());
JSONObject result = new JSONObject();
try {
result.put("platform","Android");
result.put("result_code",0);
}catch (Exception e){
e.printStackTrace();
}
return result.toString();
}
@Override
public void onMessageResponse(Object o) {
Log.e(TAG,"onMessageResponse-->" + o.toString());
}
});
}
Android侧向ArkUI-X侧传递数据
方式都一样,需要在 ArkUI-X 侧设置一下监听事件
this.bridge = Bridge.createBridge('BridgeCommon');
this.bridge!.setMessageListener((message: string) => {
if (message) {
console.log(`receive message:${message}`);
this.scanResult = message
}
return "ArkUI-X setMessageListener";
})
在 Android 侧,
ArkUIBridge extends BridgePlugin
public void sendMessageToArkUI(){
JSONObject jsonObject = new JSONObject();
try {
jsonObject.put("code","0");
jsonObject.put("msg","扫描结果");
jsonObject.put("data","scan result from Android");
}catch (Exception e){
e.printStackTrace();
}
Log.e(TAG,"toScan before sendMessage" );
sendMessage(jsonObject.toString());
}
需要注意的是,在 Android 中调用 sendMessage 方法是没有返回值的,ArkUI-X 侧收到消息后的返回值是在setMessageListener
的onMessageResponse
回调中接收的。
ArkUI-X 侧调用 Android 侧的方法
在 ArkUI-X 中
async getAppVersion(): Promise<string> {
this.initBridge();//创建 bridge 对象
let params:Record<string,Bridge.Parameter> ={
"name":"xuan",
"age":18
}
let result = await this.bridge!.callMethod('getAppVersion',params);
console.log('getAppVersion返回值:' + result)
return result!.toString();
}
在 Android
public String getAppVersion(JSONObject params){
Log.e(TAG,"getAppVersion from arkui-x,params--> " );
if(params == null){
Log.e(TAG,"is null");
}else{
Log.e(TAG,params.toString());
}
JSONObject jsonObject = new JSONObject();
try {
jsonObject.put("version",BuildConfig.VERSION_NAME);
jsonObject.put("buildVersion","getAppVersion(Object params)");
}catch (Exception e){
e.printStackTrace();
}
return jsonObject.toString();
}
需要注意的是,两侧都不支持方法重载,在 Android 侧是通过 HashMap 保存的在 BridgePlugin 中的方法并且是以方法名为 key,java.lang.reflect.Method为值。在 Android 侧的方法会被自动注册,不需要我们调用代码注册。
Android 侧调用 ArkUI-X 侧 的方法
在 ArkUI-X 中,需要自己调用registerMethod方法来注册供 native 调用的方法。
//方法声明
getString(parameters?: Record<string,Bridge.Message>):Bridge.ResultValue {
console.log(`----调用 getString:parameters-->${JSON.stringify(parameters)}`);
return 'call js getString success';
}
//注册方法
this.bridge!.registerMethod({name:"getString",method:this.getString})
在 Android 侧
JSONObject params = new JSONObject();
try {
params.put("name","xuan");
params.put("age",18);
}catch (Exception e){
e.printStackTrace();
}
Object[] paramObject = {params};
MethodData methodData = new MethodData("getString", paramObject);
callMethod(methodData);
同样的,Android 调用 ArkUI 的方法并没有返回值,需要在setMethodResultListener
的onSuccess
方法中获取
//设置调用 ArkUI-X 方法的结果回调
setMethodResultListener(new IMethodResult() {
@Override
public void onSuccess(Object o) {
Log.e(TAG,"IMethodResult#onSuccess-->" +o.toString());
}
@Override
public void onError(String s, int i, String s1) {
}
@Override
public void onMethodCancel(String s) {
}
});
注意事项
BridgePlugin 中提供给 ArkUI-X 调用的方法不支持方法重载
原因上面也说了,是因为保存的时候是用方法名作为 key 保存在 HashMap 中的,重载也没用,虽然写了不报错,但结果不保证。也看一下为啥 Android 不用自己写代码注册供 ArkUI-X调用的方法。
在ohos.ace.adapter.capability.bridge.BridgePlugin
这个类中,重点关注HashMap<String, Method> methodsMap_
这个成员变量和这几个方法:
- protected Object jsCallMethod(Object object, MethodData methodData)
- private Method findMethod(String methodName)
- private void registerMethod(String methodName, Method methods)
当 ArkUI-X 调用 Android 方法时,首先调用的是jsCallMethod
,在jsCallMethod
中首先调用findMethod
方法从methodsMap_
中获取对应的方法,找了则直接调用。没找到则反射获取 BridgePlugin 实现类中的方法,然后使用方法名做匹配,找到对应的方法。到这里也就解释了为啥不支持方法重载。也解释了为啥方法参数对应不上会有异常。
cpp 的源码在 gitee.com/arkui-x/ark…
Java 源码在 gitee.com/arkui-x/ark…
参数类型对应关系
Arkui-X 中callMethod是这么声明的
callMethod(methodName: string, parameters?: Record<string, Parameter>):
callMethod(methodName: string, ...parameters: Array<any>): Promise<ResultValue>;
sendMessage是这么声明的
sendMessage(message: Message, callback: AsyncCallback<Response>): void;
sendMessage(message: Message): Promise<Response>;
type S = number | boolean | string | null;
type T = S | Array<number> | Array<boolean> | Array<string>;
type Message = T | Record<string, T>;
type Parameter = Message;
type Response = Message;
type ResultValue = T | Map<string, T>;
在 Android 中sendMessage
public void sendMessage(Object data){}
callMethod
public void callMethod(MethodData methodData)
而 MethodData 只有两个成员变量
public class MethodData {
private String methodName_;
private Object[] Parameters_;
public MethodData(String methodName, Object[] parameter) {
this.methodName_ = methodName;
this.Parameters_ = parameter;
}
public String getMethodName() {
return this.methodName_;
}
public Object[] getMethodParameter() {
return this.Parameters_;
}
}
那么在使用的时候可以这样:
ArkUI-X主动调用 Android
在 ArkUI-X 中调用
let params:Record<string,Bridge.Parameter> ={
"name":"xuan",
"age":18
}
let result = await this.bridge!.callMethod('getAppVersion',params);
在 Android 端对应参数类型
public String getAppVersion(JSONObject params){
}
Android 主动调用 ArkUI-X
在 Android 中调用
JSONObject params = new JSONObject();
try {
params.put("name","xuan");
params.put("age",18);
}catch (Exception e){
e.printStackTrace();
}
Object[] paramObject = {params};
MethodData methodData = new MethodData("getString", paramObject);
callMethod(methodData);
在 ArkUI-X 中对应类型
getString(parameters?: Record<string,Bridge.Message>):Bridge.ResultValue {
console.log(`----调用 getString:parameters-->${JSON.stringify(parameters)}`);
return 'call js getString success';
}
BrigePlugin的bridgeType_
BrigePlugin提供了一个可以指定bridgeType_
的构造方法,
如果我们不指定类型的话,默认就是 BridgeType.JSON_TYPE
,传一些非二进制的数据。但假如我们需要穿一些二进制数据,比如图片、音视频数据等,可以指定为BridgeType.BINARY_TYPE
。
怎样学习鸿蒙?
首先必学的是开发语言 ArkTS,这是重中之重,然后就是ArkUI声明式UI开发、Stage模型、网络/数据库管理、分布式应用开发、进程间通信与线程间通信技术、OpenHarmony多媒体技术……。中间还有许多的知识点,都整理成思维导图来分享给大家~
此外,小编精心准备了一份联合鸿蒙官方发布笔记整理收纳的《鸿蒙开发学习笔记》,内容包含ArkTS、ArkUI、Web开发、应用模型、资源分类…等知识点。
【有需要的小伙伴,可以扫描下方二维码免费领取!!!】

快速入门
- 开发准备
- 构建第一个ArkTS应用(Stage模型)
- 构建第一个ArkTS应用(FA模型)
- 构建第一个JS应用(FA模型)
开发基础知识
- 应用程序包基础知识
- 应用配置文件(Stage模型)
- 应用配置文件概述(FA模型)
资源分类与访问
- 资源分类与访问
- 创建资源目录和资源文件
- 资源访问
学习ArkTs语言
- 初识ArkTS语言
- 基本语法
- 状态管理
- 其他状态管理
- 渲染控制
基于ArkTS声明式开发范式
- UI开发(ArkTS声明式开发范式)概述
- 开发布局
- 添加组件
- 显示图片
- 使用动画
- 支持交互事件
- 性能提升的推荐方法
兼容JS的类Web开发范式
- 概述
- 框架说明
- 构建用户界面
- 常见组件开发指导
- 动效开发指导
- 自定义组件
Web组件
- 概述
- 设置基本属性和事件
- 并发
- 窗口管理
- WebGL
- 媒体
- 安全
- 网络与连接
- 电话服务
- 数据管理
- …
应用模型
- 概述
- Stage模型开发指导
- FA模型开发指导
2024完整鸿蒙学习资料领取方式:扫描下方二维码即可
