HarmonyOS JS FA 調(diào)用 Java PA 機制
51CTO和華為官方合作共建的鴻蒙技術(shù)社區(qū)
實現(xiàn)效果
一、項目介紹
本項目使用模擬文件下載進度變化的功能來給你展示JS FA訂閱JAVA PA的能力,訂閱之后JS可以一直實時獲取到JAVA返回的進度數(shù)據(jù)來更新JS界面的進度條。另外,文件模擬下載完成跳轉(zhuǎn)到一個求積的頁面,在這個頁面輸入兩個數(shù),點擊求積按鈕會給你展示JS FA調(diào)用JAVA PA的能力,此處并不像訂閱一樣可以一直獲取到j(luò)ava返回的數(shù)據(jù),采用的模式是調(diào)用一次返回一次數(shù)據(jù)。
通過本項目,是想讓你了解如下知識點:
1) FeatureAbility.callAbility(OBJECT):調(diào)用PA能力。
2) FeatureAbility.subscribeAbilityEvent(OBJECT, Function):訂閱PA能力。
3) FeatureAbility.unsubscribeAbilityEvent(OBJECT):取消訂閱PA能力。
二、代碼結(jié)構(gòu)解讀

1、java/ServiceAbility : java與js的通信代碼;
2、java-RequestParam :請求參數(shù)的實體類;
3、js-pages-index.hml : js模擬文件下載頁;
4、js-pages-index.js : js訂閱java pa代碼;
5、js-calculate-calculate.hml : js求積頁面;
6、js-calculate-calculate.js : 調(diào)用java pa代碼;
7、config.json : js、java的配置文件,里面包括頁面配置、service配置、窗體配置等等。
三、新建js project
右擊—new—new project 。

選擇模板—next。

輸入項目名稱、選擇項目類型(單選)、api版本,設(shè)備類型,點擊finish即可。

四、訂閱PA解讀
點擊下載按鈕,向java端發(fā)送訂閱請求。
- /**
- * 請求開啟訂閱模式
- */
- subscribe: async function() {
- this.isShow = true; // 顯示進度條內(nèi)容
- var that = this;
- var actionData = {};
- actionData.firstNum = that.message;
- var action = {};
- action.bundleName = 'com.example.javajscommunication'; // Ability的包名稱,需要與PA端匹配,區(qū)分大小寫
- action.abilityName = 'com.example.javajscommunication.ServiceAbility'; // Ability名稱,需要與PA端匹配,區(qū)分大小寫
- action.messageCode = ACTION_MESSAGE_CODE_PLUS_SUB; // Ability操作碼(操作碼定義PA的業(yè)務(wù)功能,需要與PA端約定)
- action.data = actionData; // 發(fā)送到Ability的數(shù)據(jù),數(shù)據(jù)字段名稱需要與PA端約定
- action.abilityType = ABILITY_TYPE_EXTERNAL; // Ability類型,對應(yīng)PA端不同的實現(xiàn)方式
- action.syncOption = ACTION_SYNC; // PA側(cè)請求消息處理同步/異步選項 0:同步方式,默認(rèn)方式。 1:異步方式
- await FeatureAbility.subscribeAbilityEvent(action, function (callbackData) {
- var callbackJson = JSON.parse(callbackData); // json字符串反序列化
- that.message = callbackJson.data.abilityEvent;
- if (that.message == 100) { // message 為100時進行跳轉(zhuǎn)計算頁面
- router.push({
- uri: "pages/calculate/calculate"
- })
- that.unsubscribe(); // 取消訂閱
- that.isShow = false; // 隱藏進度條
- }
- })
- }
java端在ServiceAbility中對訂閱請求進行處理,在內(nèi)部類MyRemote的onRemoteRequest方法中根據(jù)code參數(shù)來判斷請求類型進行相應(yīng)處理。
- case ACTION_MESSAGE_CODE_PLUS_SUB: {
- go = true; // 開啟可以下載狀態(tài)
- remoteObjectHandler = data.readRemoteObject(); // 獲取請求參數(shù)對象
- String zsonStr = data.readString(); // 獲取參數(shù)字符串
- try {
- param = ZSONObject.stringToClass(zsonStr, RequestParam.class); // 字符串對象轉(zhuǎn)成RequestParam實例
- } catch (RuntimeException e) {
- }
- startNotify(param); // 給js端發(fā)送信息
- Map<String, Object> zsonResult = new HashMap<String, Object>();// 返回結(jié)果,關(guān)鍵字段應(yīng)與Js方協(xié)商
- zsonResult.put("code", SUCCESS);
- reply.writeString(ZSONObject.toZSONString(zsonResult)); // map 對象轉(zhuǎn)成json字符串,并返回給js端
- return true;
- }
java端開啟線程,按照5*3 每15毫秒的頻率返回數(shù)據(jù)給js端。這里java發(fā)送給js的數(shù)據(jù),js端會通過訂閱java pa的回調(diào)函數(shù)中而實時獲取到。
- /**
- * 開啟線程,按照5*3 每15毫秒的頻率返回數(shù)據(jù)給js端。這里java發(fā)送給js的數(shù)據(jù),
- * js端會通過訂閱java pa的回調(diào)函數(shù)中而實時獲取到
- */
- public void startNotify(RequestParam param) {
- number = param.getFirstNum(); // 獲取當(dāng)前進度值從請求中獲取
- new Thread(() -> { // 開啟線程
- while (go) {
- try {
- Thread.sleep(5 * 3); // 線程睡眠15毫秒后繼續(xù)往下執(zhí)行
- MessageParcel data = MessageParcel.obtain(); // 創(chuàng)建索引為0的空MessageParcel對象
- MessageParcel reply = MessageParcel.obtain();
- zsonEvent.put("abilityEvent", number++);
- if (number == 101) { // number超過100 go狀態(tài)設(shè)為false 下載結(jié)束
- go = false;
- }
- data.writeString(ZSONObject.toZSONString(zsonEvent)); // 數(shù)據(jù)存到MessageParcel載體
- remoteObjectHandler.sendRequest(100, data, reply, option); // 發(fā)送
- reply.reclaim(); // 回收
- data.reclaim();
- } catch (RemoteException | InterruptedException e) {
- break;
- }
- }
- }).start();
- }
js頁面點擊取消按鈕,取消訂閱模式, java端停止返回數(shù)據(jù)。
js端代碼如下:
- /**
- * 請求取消訂閱, java端停止返回數(shù)據(jù)
- */
- unsubscribe: async function() {
- var action = {};
- action.bundleName = 'com.example.javajscommunication'; // Ability的包名稱,需要與PA端匹配,區(qū)分大小寫
- action.abilityName = 'com.example.javajscommunication.ServiceAbility'; // Ability名稱,需要與PA端匹配,區(qū)分大小寫
- action.messageCode = ACTION_MESSAGE_CODE_PLUS_UNSUB; // Ability操作碼(操作碼定義PA的業(yè)務(wù)功能,需要與PA端約定)
- action.abilityType = ABILITY_TYPE_EXTERNAL; // Ability類型,對應(yīng)PA端不同的實現(xiàn)方式
- action.syncOption = ACTION_SYNC; // PA側(cè)請求消息處理同步/異步選項 0:同步方式,默認(rèn)方式。 1:異步方式
- var result = await FeatureAbility.unsubscribeAbilityEvent(action); // 取消訂閱
- var ret = JSON.parse(result); // 反序列化,
- if (ret.code == 0) {
- prompt.showToast({
- message: '取消下載成功'
- })
- } else {
- prompt.showToast({
- message: '取消下載失敗'
- })
- }
- }
java端service代碼如下:
- case ACTION_MESSAGE_CODE_PLUS_UNSUB: {
- go = false; // 停止方法startNotify中的while循環(huán),停止往js端發(fā)送消息
- Map<String, Object> zsonResult = new HashMap<String, Object>();
- zsonResult.put("code", SUCCESS);
- reply.writeString(ZSONObject.toZSONString(zsonResult)); // 響應(yīng)js端
- return true;
- }
五、調(diào)用PA解讀
獲取input輸入的值,作為js端傳遞過去的值。
- /**
- * 取傳過去的第一個值
- */
- numOne (e){
- this.numOne = e.value
- },
- /**
- * 獲取傳過去的第二個值
- */
- numTwo (e){
- this.numTwo = e.value
- }
點擊求積按鈕 發(fā)送調(diào)用模式的請求。
- calculate: async function() {
- var actionData = {}; // key值對應(yīng)PA端的RequestParam類的成員字段
- actionData.firstNum = this.numOne;
- actionData.secondNum = this.numTwo;
- var action = {};
- action.bundleName = 'com.example.javajscommunication'; // Ability的包名稱,需要與PA端匹配,區(qū)分大小寫
- action.abilityName = 'com.example.javajscommunication.ServiceAbility'; // Ability名稱,需要與PA端匹配,區(qū)分大小寫
- action.messageCode = ACTION_MESSAGE_CODE_PLUS; // Ability操作碼(操作碼定義PA的業(yè)務(wù)功能,需要與PA端約定)
- action.data = actionData; // 發(fā)送到Ability的數(shù)據(jù),數(shù)據(jù)字段名稱需要與PA端約定
- action.abilityType = ABILITY_TYPE_EXTERNAL; // Ability類型,對應(yīng)PA端不同的實現(xiàn)方式
- action.syncOption = ACTION_SYNC; // PA側(cè)請求消息處理同步/異步選項 0:同步方式,默認(rèn)方式。 1:異步方式
- var result = await FeatureAbility.callAbility(action);
- var ret = JSON.parse(result);
- if (ret.code == 0) {
- this.message = 'java端傳回的數(shù)據(jù)為:' + JSON.stringify(ret.abilityResult);
- } else {
- this.message = 'java端傳回的數(shù)據(jù)報錯' + JSON.stringify(ret.code);
- }
- },
java端在ServiceAbility中對訂閱請求進行處理,在內(nèi)部類MyRemote的onRemoteRequest方法中根據(jù)code參數(shù)來判斷請求類型進行相應(yīng)處理。這里java發(fā)送給js的數(shù)據(jù),js端會通過調(diào)用java pa的結(jié)果而獲取到。
- case ACTION_MESSAGE_CODE_PLUS: {
- String zsonStr = data.readString(); // 獲取傳入?yún)?shù)的字符串
- RequestParam param = new RequestParam();
- try {
- param = ZSONObject.stringToClass(zsonStr, RequestParam.class); // 字符串對象轉(zhuǎn)成RequestParam實例
- } catch (RuntimeException e) {
- }
- // 返回結(jié)果僅支持可序列化的Object類型
- Map<String, Object> zsonResult = new HashMap<>();
- zsonResult.put("code", SUCCESS);
- zsonResult.put("abilityResult", param.getFirstNum() + " * " + param.getSecondNum() + " = " + (param.getFirstNum() * param.getSecondNum()));
- reply.writeString(ZSONObject.toZSONString(zsonResult)); // 數(shù)據(jù)返回給js端
- return true;
- }
返回到前一個頁面,這里在頁面js中import router from ‘@system.router’,然后利用router對象的相關(guān)方法返回。
- back(){
- router.back() // 返回到前一個頁面
- }
六、代碼參考
https://gitee.com/chinasoft6_ohos/java-js-communication
51CTO和華為官方合作共建的鴻蒙技術(shù)社區(qū)