https://harmonyos.51cto.com
引言
上一篇文章我们已经了解到了Ability的概念,还有JS FA调用Java PA两种方式,Ability和Internal Ability的区别。
因为刚开始学习,一般是使用Internal Ability比较多,所以我们借助具体参照官方Gitee仓库的示例来一起学习一下Internal Ability的具体调用方法。
JS FA调用Java PA — InternalAbility调用方式
JS FA端(Internal Ability)
FA端相对PA端比较简单,官方提供的API也只有三个:
- FeatureAbility.callAbility(OBJECT):调用PA能力
- FeatureAbility.subscribeAbilityEvent(OBJECT, Function):订阅PA能力
- FeatureAbility.unsubscribeAbilityEvent(OBJECT):取消订阅PA能力
怎么理解这三个的区别呢?其实很简单,假设我们现在要做一个获取手机电池情况的应用,它具备三个功能分别对应的API如下:
- 获取手机电量———调用PA能力
- 监听手机电量变化(电量变化就给用户发送通知)———订阅PA能力———订阅PA能力
- 取消监听手机电量变化———取消订阅PA能力
这样相信大家大概能理解这几个接口的区别了。
另外提一下,这几个API支持大部分富设备。
注:这三个接口的返回值均为Promise类型,格式为JSON字符串
1.参数初始化
首先我们来看一下参数,虽然官方文档把这三个API的接口参数分成了三部分描述,但是其实参数都一样,唯一区别就是,FeatureAbility.callAbility的有Data这个请求参数
bundleName:Ability的包名称,需要与PA端匹配,区分大小写。
abilityName:Ability名称,需要与PA端匹配,区分大小写。
messageCode:Ability操作码(操作码定义PA的业务功能,需要与PA端约定),可以自己设置,不同的码对应着要处理的不同业务。
abilityType:Ability类型,对应PA端不同的实现方式:
- 0:Ability调用方式
- 1:Internal Ability调用方式
data:发送到Ability的数据(根据不同的业务携带相应的业务数据,数据字段名称需要与PA端约定),只有FeatureAbility.callAbility接口有。
syncOption:PA侧请求消息处理同步/异步选项,非必填,默认使用同步方式。当前异步方式仅支持AbilityType为Internal Ability类型。
- 0:同步方式,默认方式。
- 1:异步方式。
既然参数都一样,那为什么不统一封装起来,提高代码复用性呢,那第一步是先要封装一个参数初始化函数:
我们在自己的js页面中,先创建一个action对象,初始化好后进行返回。
initAction: function (code) {
var actionData = {};
var action = {};
action.bundleName = "ohos.samples.jscalljava";
action.abilityName = "BatteryInternalAbility";
action.messageCode = code;
action.data = actionData;
action.abilityType = 1;
action.syncOption = 0;
return action;
}
2.FeatureAbility.callAbility(OBJECT)
我们知道了获取手机电量这个功能是基于调用PA能力,下面我们来来看看怎么实现该部分代码
getBatteryLevel: async function () {
try {
var action = this.initAction(1001); //给封装好的初始化函数传递操作码,确定要调用的业务
var result = await FeatureAbility.callAbility(action); //调用API
console.info(" result = " + result);
this.showToast(result); //在界面上弹出结果
} catch (pluginError) {
console.error("getBatteryLevel : Plugin Error = " + pluginError);
}
},
3.FeatureAbility.subscribeAbilityEvent(OBJECT)
接着是监听手机电量变化:
batteryLevelSubscribe: async function () {
try {
var action = this.initAction(1002); //给封装好的初始化函数传递操作码,确定要调用的业务
var that = this;
var result = await FeatureAbility.subscribeAbilityEvent(action,function (batteryLevel) { //调用订阅服务API
console.info(" batteryLevel info is: " + batteryLevel);
var batteryData = JSON.parse(batteryLevel).data; //将Json字符串转换为对象,并获取接口返回数据
that.showToast(" batteryState change: " + batteryData.msg);
});
this.showToast(" subscribe result " + result);
console.info(" subscribeCommonEvent result = " + result);
} catch (pluginError) {
console.error("subscribeCommonEvent error : result= " + result + JSON.stringify(pluginError));
}
},
4.FeatureAbility.unsubscribeAbilityEvent(OBJECT)
最后是取消订阅:
batteryLevelUnSubscribe: async function () {
try {
var action = this.initAction(1003);
var result = await FeatureAbility.unsubscribeAbilityEvent(action);
FeatureAbility.callAbility(action);
this.showToast("unsubscribe result " + result);
} catch (pluginError) {
console.error("batteryLevelUnSubscribe error : " + JSON.stringify(pluginError));
this.showToast("batteryLevelUnSubscribe error : " + JSON.stringify(pluginError));
}
},
完整示例
具体参照官方Gitee仓库的示例
https://gitee.com/harmonyos/harmonyos_app_samples/tree/master/JSUI/JsCallJava
import prompt from '@system.prompt'
export default {
batteryLevel: function () {
this.getBatteryLevel();
},
batterySubscribe: function () {
this.batteryLevelSubscribe();
},
batteryUnSubscribe: function () {
this.batteryLevelUnSubscribe();
},
initAction: function (code) {
var actionData = {};
var action = {};
action.bundleName = "ohos.samples.jscalljava";
action.abilityName = "BatteryInternalAbility";
action.messageCode = code;
action.data = actionData;
action.abilityType = 1;
action.syncOption = 0;
return action;
},
getBatteryLevel: async function () {
try {
var action = this.initAction(1001); //给封装好的初始化函数传递操作码,确定要调用的业务
var result = await FeatureAbility.callAbility(action); //调用API
console.info(" result = " + result);
this.showToast(result); //在界面上弹出结果
} catch (pluginError) {
console.error("getBatteryLevel : Plugin Error = " + pluginError);
}
},
batteryLevelSubscribe: async function () {
try {
var action = this.initAction(1002); //给封装好的初始化函数传递操作码,确定要调用的业务
var that = this;
var result = await FeatureAbility.subscribeAbilityEvent(action,function (batteryLevel) { //调用订阅服务API
console.info(" batteryLevel info is: " + batteryLevel);
var batteryData = JSON.parse(batteryLevel).data; //将Json字符串转换为对象,并获取接口返回数据
that.showToast(" batteryState change: " + batteryData.msg);
});
this.showToast(" subscribe result " + result);
console.info(" subscribeCommonEvent result = " + result);
} catch (pluginError) {
console.error("subscribeCommonEvent error : result= " + result + JSON.stringify(pluginError));
}
},
batteryLevelUnSubscribe: async function () {
try {
var action = this.initAction(1003);
var result = await FeatureAbility.unsubscribeAbilityEvent(action);
FeatureAbility.callAbility(action);
this.showToast("unsubscribe result " + result);
} catch (pluginError) {
console.error("batteryLevelUnSubscribe error : " + JSON.stringify(pluginError));
this.showToast("batteryLevelUnSubscribe error : " + JSON.stringify(pluginError));
}
},
showToast: function (msg) {
prompt.showToast({
message: msg
});
}
}
Java PA端(Internal Ability)
1.导入ohos相关接口包
在java目录下新建一个Ability文件
package ohos.samples.jscalljava;
import ohos.ace.ability.AceInternalAbility;
import ohos.batterymanager.BatteryInfo;
import ohos.event.commonevent.CommonEventData;
import ohos.event.commonevent.CommonEventManager;
import ohos.event.commonevent.CommonEventSubscribeInfo;
import ohos.event.commonevent.CommonEventSubscriber;
import ohos.event.commonevent.CommonEventSupport;
import ohos.event.commonevent.MatchingSkills;
import ohos.hiviewdfx.HiLog;
import ohos.hiviewdfx.HiLogLabel;
import ohos.rpc.IRemoteObject;
import ohos.rpc.MessageOption;
import ohos.rpc.MessageParcel;
import ohos.rpc.RemoteException;
2.创建一个继承Ability的类
public class BatteryInternalAbility extends AceInternalAbility {
private static final int BATTERY_LEVEL_NOT_AVAILABLE = 1001; // 与FA协商好的Ability操作码,对应不同业务功能
private static final int BATTERY_SUBSCRIBE_FAILURE = 1002; // 与FA协商好的Ability操作码,对应不同业务功能
private static final int BATTERY_UNSUBSCRIBE_FAILURE = 1003; // 与FA协商好的Ability操作码,对应不同业务功能
private static final String TAG = BatteryInternalAbility.class.getSimpleName();
private static final HiLogLabel LABEL_LOG = new HiLogLabel(3, 0xD000F00, TAG);// 定义日志标签
private static final int DEFAULT_TYPE = 0;
private static BatteryInternalAbility instance;
private static final String BUNDLE_NAME = "ohos.samples.jscalljava";
private static final String ABILITY_NAME = "BatteryInternalAbility";
private CommonEventSubscriber subscriber;
// 如果多个Ability实例都需要注册当前InternalAbility实例,需要更改构造函数,设定自己的bundleName和abilityName
private BatteryInternalAbility() {
super(BUNDLE_NAME, ABILITY_NAME);
}
3.封装业务逻辑调用
public boolean onRemoteRequest(int code, MessageParcel data, MessageParcel reply, MessageOption option) {
switch (code) {
case BATTERY_LEVEL_NOT_AVAILABLE:
reply.writeString(getBatteryInfo());
break;
case BATTERY_SUBSCRIBE_FAILURE:
subscribeEvent(data, reply, option);
break;
case BATTERY_UNSUBSCRIBE_FAILURE:
unSubscribeBatteryEvent(reply);
break;
default:
reply.writeString("service not defined");
return false;
}
return true;
}
4.调用onRemoteRequest接口与FA完成交互逻辑
注:该接口返回值为布尔值,操作成功返回true,否则返回false。
private void subscribeEvent(MessageParcel data, MessageParcel reply, MessageOption option) {
MatchingSkills matchingSkills = new MatchingSkills();
matchingSkills.addEvent(CommonEventSupport.COMMON_EVENT_BATTERY_CHANGED);
IRemoteObject notifier = data.readRemoteObject();
CommonEventSubscribeInfo subscribeInfo = new CommonEventSubscribeInfo(matchingSkills);
subscriber = new CommonEventSubscriber(subscribeInfo) {
@Override
public void onReceiveEvent(CommonEventData commonEventData) {
replyMsg(notifier);
}
};
if (option.getFlags() == MessageOption.TF_SYNC) {
reply.writeString("subscribe common event success");
}
try {
CommonEventManager.subscribeCommonEvent(subscriber);
reply.writeString(" subscribe common event success");
} catch (RemoteException e) {
HiLog.info(LABEL_LOG, "%{public}s", "RemoteException in subscribeNotificationEvents!");
}
}
private void replyMsg(IRemoteObject notifier) {
MessageParcel notifyData = MessageParcel.obtain();
notifyData.writeString("{\"msg\":\"" + getBatteryInfo() + "\"}");
try {
notifier.sendRequest(DEFAULT_TYPE, notifyData, MessageParcel.obtain(), new MessageOption());
} catch (RemoteException exception) {
HiLog.info(LABEL_LOG, "%{public}s", "replyMsg RemoteException !");
} finally {
notifyData.reclaim();
}
}
private String getBatteryInfo() {
StringBuilder stringBuilder = new StringBuilder();
boolean isCharging = getChargingStatus();
double batteryValue = getBatteryLevel();
stringBuilder.append(batteryValue).append(" % Battery Left").append(System.lineSeparator())
.append("isCharging: ")
.append(isCharging);
return stringBuilder.toString();
}
private void unSubscribeBatteryEvent(MessageParcel reply) {
try {
CommonEventManager.unsubscribeCommonEvent(subscriber);
reply.writeString("Unsubscribe common event success!");
} catch (RemoteException | IllegalArgumentException exception) {
reply.writeString("Battery Unsubscribe failed!");
HiLog.info(LABEL_LOG, "%{public}s", "Battery Unsubscribe failed!");
}
subscriber = null;
}
private int getBatteryLevel() {
BatteryInfo batteryInfo = new BatteryInfo();
return batteryInfo.getCapacity();
}
private boolean getChargingStatus() {
BatteryInfo batteryInfo = new BatteryInfo();
BatteryInfo.BatteryChargeState batteryStatus = batteryInfo.getChargingStatus();
return (batteryStatus == BatteryInfo.BatteryChargeState.ENABLE
|| batteryStatus == BatteryInfo.BatteryChargeState.FULL);
}
/**
* BatteryInternalAbility
*
* @return If the instance is NULL, Get new instance. Otherwise, instance is returned.
*/
public static BatteryInternalAbility getInstance() {
if (instance == null) {
synchronized (BatteryInternalAbility.class) {
if (instance == null) {
instance = new BatteryInternalAbility();
}
}
}
return instance;
}
5.注册和注销InternalAbility
/**
* Internal ability 注册接口
*/
public void register() {
this.setInternalAbilityHandler(this::onRemoteRequest);
}
/**
* Internal ability 注销接口
*/
public void deregister() {
this.setInternalAbilityHandler(null);
}
完整示例
具体参照官方Gitee仓库的示例
https://gitee.com/harmonyos/harmonyos_app_samples/tree/master/JSUI/JsCallJava
package ohos.samples.jscalljava;
import ohos.ace.ability.AceInternalAbility;
import ohos.batterymanager.BatteryInfo;
import ohos.event.commonevent.CommonEventData;
import ohos.event.commonevent.CommonEventManager;
import ohos.event.commonevent.CommonEventSubscribeInfo;
import ohos.event.commonevent.CommonEventSubscriber;
import ohos.event.commonevent.CommonEventSupport;
import ohos.event.commonevent.MatchingSkills;
import ohos.hiviewdfx.HiLog;
import ohos.hiviewdfx.HiLogLabel;
import ohos.rpc.IRemoteObject;
import ohos.rpc.MessageOption;
import ohos.rpc.MessageParcel;
import ohos.rpc.RemoteException;
/**
* Internal Ability
*/
public class BatteryInternalAbility extends AceInternalAbility {
private static final int BATTERY_LEVEL_NOT_AVAILABLE = 1001; // 与FA协商好的Ability操作码,对应不同业务功能
private static final int BATTERY_SUBSCRIBE_FAILURE = 1002; // 与FA协商好的Ability操作码,对应不同业务功能
private static final int BATTERY_UNSUBSCRIBE_FAILURE = 1003; // 与FA协商好的Ability操作码,对应不同业务功能
private static final String TAG = BatteryInternalAbility.class.getSimpleName();
private static final HiLogLabel LABEL_LOG = new HiLogLabel(3, 0xD000F00, TAG);// 定义日志标签
private static final int DEFAULT_TYPE = 0;
private static BatteryInternalAbility instance;
private static final String BUNDLE_NAME = "ohos.samples.jscalljava";
private static final String ABILITY_NAME = "BatteryInternalAbility";
private CommonEventSubscriber subscriber;
private BatteryInternalAbility() { // 如果多个Ability实例都需要注册当前InternalAbility实例,需要更改构造函数,设定自己的bundleName和abilityName
super(BUNDLE_NAME, ABILITY_NAME);
}
public boolean onRemoteRequest(int code, MessageParcel data, MessageParcel reply, MessageOption option) {
switch (code) {
case BATTERY_LEVEL_NOT_AVAILABLE:
reply.writeString(getBatteryInfo());
break;
case BATTERY_SUBSCRIBE_FAILURE:
subscribeEvent(data, reply, option);
break;
case BATTERY_UNSUBSCRIBE_FAILURE:
unSubscribeBatteryEvent(reply);
break;
default:
reply.writeString("service not defined");
return false;
}
return true;
}
private void subscribeEvent(MessageParcel data, MessageParcel reply, MessageOption option) {
MatchingSkills matchingSkills = new MatchingSkills();
matchingSkills.addEvent(CommonEventSupport.COMMON_EVENT_BATTERY_CHANGED);
IRemoteObject notifier = data.readRemoteObject();
CommonEventSubscribeInfo subscribeInfo = new CommonEventSubscribeInfo(matchingSkills);
subscriber = new CommonEventSubscriber(subscribeInfo) {
@Override
public void onReceiveEvent(CommonEventData commonEventData) {
replyMsg(notifier);
}
};
if (option.getFlags() == MessageOption.TF_SYNC) {
reply.writeString("subscribe common event success");
}
try {
CommonEventManager.subscribeCommonEvent(subscriber);
reply.writeString(" subscribe common event success");
} catch (RemoteException e) {
HiLog.info(LABEL_LOG, "%{public}s", "RemoteException in subscribeNotificationEvents!");
}
}
private void replyMsg(IRemoteObject notifier) {
MessageParcel notifyData = MessageParcel.obtain();
notifyData.writeString("{\"msg\":\"" + getBatteryInfo() + "\"}");
try {
notifier.sendRequest(DEFAULT_TYPE, notifyData, MessageParcel.obtain(), new MessageOption());
} catch (RemoteException exception) {
HiLog.info(LABEL_LOG, "%{public}s", "replyMsg RemoteException !");
} finally {
notifyData.reclaim();
}
}
private String getBatteryInfo() {
StringBuilder stringBuilder = new StringBuilder();
boolean isCharging = getChargingStatus();
double batteryValue = getBatteryLevel();
stringBuilder.append(batteryValue).append(" % Battery Left").append(System.lineSeparator())
.append("isCharging: ")
.append(isCharging);
return stringBuilder.toString();
}
private void unSubscribeBatteryEvent(MessageParcel reply) {
try {
CommonEventManager.unsubscribeCommonEvent(subscriber);
reply.writeString("Unsubscribe common event success!");
} catch (RemoteException | IllegalArgumentException exception) {
reply.writeString("Battery Unsubscribe failed!");
HiLog.info(LABEL_LOG, "%{public}s", "Battery Unsubscribe failed!");
}
subscriber = null;
}
private int getBatteryLevel() {
BatteryInfo batteryInfo = new BatteryInfo();
return batteryInfo.getCapacity();
}
private boolean getChargingStatus() {
BatteryInfo batteryInfo = new BatteryInfo();
BatteryInfo.BatteryChargeState batteryStatus = batteryInfo.getChargingStatus();
return (batteryStatus == BatteryInfo.BatteryChargeState.ENABLE
|| batteryStatus == BatteryInfo.BatteryChargeState.FULL);
}
/**
* BatteryInternalAbility
*
* @return If the instance is NULL, Get new instance. Otherwise, instance is returned.
*/
public static BatteryInternalAbility getInstance() {
if (instance == null) {
synchronized (BatteryInternalAbility.class) {
if (instance == null) {
instance = new BatteryInternalAbility();
}
}
}
return instance;
}
/**
* Internal ability 注册接口
*/
public void register() {
this.setInternalAbilityHandler(this::onRemoteRequest);
}
/**
* Internal ability 注销接口
*/
public void deregister() {
this.setInternalAbilityHandler(null);
}
}
代码参考
具体参照官方Gitee仓库的示例
https://gitee.com/harmonyos/harmonyos_app_samples/tree/master/JSUI/JsCallJava
方便大家取到代码,已将源码压缩文件添加至附件