(HarmonyOS)JS FA调用Java PA(二)Internal Ability调用方式

引言

上一篇文章我们已经了解到了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也只有三个:

怎么理解这三个的区别呢?其实很简单,假设我们现在要做一个获取手机电池情况的应用,它具备三个功能分别对应的API如下:

  • 获取手机电量———调用PA能力
  • 监听手机电量变化(电量变化就给用户发送通知)———订阅PA能力———订阅PA能力
  • 取消监听手机电量变化———取消订阅PA能力

这样相信大家大概能理解这几个接口的区别了。

另外提一下,这几个API支持大部分富设备。

注:这三个接口的返回值均为Promise类型,格式为JSON字符串

image.png[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-u0WAzvmw-1644679261733)(FAcallPA-二/image-20220212143335645.png)]

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对象,初始化好后进行返回。

image.png[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-wFRqLaXJ-1644679261735)(FAcallPA-二/image-20220212163621679.png)]

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完成交互逻辑

image.png[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-NHp4TC1d-1644679261737)(FAcallPA-二/image-20220212220918837.png)]

注:该接口返回值为布尔值,操作成功返回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
方便大家取到代码,已将源码压缩文件添加至附件

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值