【FFH】JSFA调用PA(二) Internal Ability调用方式 原创 精华

Hagon
发布于 2022-2-12 22:22
浏览
3收藏

春节不停更,此文正在参加「星光计划-春节更帖活动」
@[TOC](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字符串

【FFH】JSFA调用PA(二) Internal Ability调用方式-鸿蒙开发者社区【FFH】JSFA调用PA(二) Internal Ability调用方式-鸿蒙开发者社区

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

【FFH】JSFA调用PA(二) Internal Ability调用方式-鸿蒙开发者社区【FFH】JSFA调用PA(二) Internal Ability调用方式-鸿蒙开发者社区

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

【FFH】JSFA调用PA(二) Internal Ability调用方式-鸿蒙开发者社区【FFH】JSFA调用PA(二) Internal Ability调用方式-鸿蒙开发者社区

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

©著作权归作者所有,如需转载,请注明出处,否则将追究法律责任
JsCallJava.zip 91.44K 9次下载
已于2022-2-14 13:40:23修改
4
收藏 3
回复
举报
2条回复
按时间正序
/
按时间倒序
Hagon
Hagon
Hagon
回复
2022-2-14 13:45:02
回复
    相关推荐