# JavaJsCommunication **Repository Path**: chinasoft6_ohos/java-js-communication ## Basic Information - **Project Name**: JavaJsCommunication - **Description**: Js FA 调用 Java PA示例 - **Primary Language**: Unknown - **License**: Apache-2.0 - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 2 - **Forks**: 1 - **Created**: 2021-08-05 - **Last Updated**: 2022-09-06 ## Categories & Tags **Categories**: harmonyos-toolkit **Tags**: None ## README # HarmonyOS JS FA 调用 JAVA PA 机制 #### 实现效果 ![ddd.gif](https://harmonyos.oss-cn-beijing.aliyuncs.com/images/202108/758b309146c47e6800990704327a7ec7f8ba74.gif?x-oss-process=image/resize,w_362,h_647) #### 一、项目介绍     本项目使用模拟文件下载进度变化的功能来给你展示JS FA订阅JAVA PA的能力,订阅之后JS可以一直实时获取到JAVA返回的进度数据来更新JS界面的进度条。另外,文件模拟下载完成跳转到一个求积的页面,在这个页面输入两个数,点击求积按钮会给你展示JS FA调用JAVA PA的能力,此处并不像订阅一样可以一直获取到java返回的数据,采用的模式是调用一次返回一次数据。     通过本项目,是想让你了解如下知识点: ​ 1) FeatureAbility.callAbility(OBJECT):调用PA能力。 ​ 2) FeatureAbility.subscribeAbilityEvent(OBJECT, Function):订阅PA能力。 ​ 3) FeatureAbility.unsubscribeAbilityEvent(OBJECT):取消订阅PA能力。 #### 二、代码结构解读 ![屏幕截图 20210802 100439.png](https://harmonyos.oss-cn-beijing.aliyuncs.com/images/202108/54253b321c9979db196519227add8982618d91.png?x-oss-process=image/resize,w_463,h_694)     1、java/ServiceAbility : java与js的通信代码;     2、java-RequestParam :请求参数的实体类;     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 : 调用java pa代码;     7、config.json : js、java的配置文件,里面包括页面配置、service配置、窗体配置等等。 #### 三、新建js project 1. 右击—new—new project 。 ![屏幕截图 20210802 112335.png](https://harmonyos.oss-cn-beijing.aliyuncs.com/images/202108/19b33466038f939c350678efb908af021a28d0.png?x-oss-process=image/resize,w_625,h_424) 2. 选择模板—next。 ![屏幕截图 20210802 112527.png](https://harmonyos.oss-cn-beijing.aliyuncs.com/images/202108/b53a00965169ba61981710617bbfaa247120c9.png?x-oss-process=image/resize,w_1259,h_747) 3. 输入项目名称、选择项目类型(单选)、api版本,设备类型,点击finish即可。 ![屏幕截图 20210802 112653.png](https://harmonyos.oss-cn-beijing.aliyuncs.com/images/202108/88bd6f3311025464dfe7824e29d6ac4612b71f.png?x-oss-process=image/resize,w_1207,h_731) #### 四、订阅PA解读 1. 点击下载按钮,向java端发送订阅请求。 ```javascript /** * 请求开启订阅模式 */ subscribe: async function() { this.isShow = true; // 显示进度条内容 var that = this; var actionData = {}; actionData.firstNum = that.message; var action = {}; action.bundleName = 'com.example.javajscommunication'; // Ability的包名称,需要与PA端匹配,区分大小写 action.abilityName = 'com.example.javajscommunication.ServiceAbility'; // Ability名称,需要与PA端匹配,区分大小写 action.messageCode = ACTION_MESSAGE_CODE_PLUS_SUB; // Ability操作码(操作码定义PA的业务功能,需要与PA端约定) action.data = actionData; // 发送到Ability的数据,数据字段名称需要与PA端约定 action.abilityType = ABILITY_TYPE_EXTERNAL; // Ability类型,对应PA端不同的实现方式 action.syncOption = ACTION_SYNC; // PA侧请求消息处理同步/异步选项 0:同步方式,默认方式。 1:异步方式 await FeatureAbility.subscribeAbilityEvent(action, function (callbackData) { var callbackJson = JSON.parse(callbackData); // json字符串反序列化 that.message = callbackJson.data.abilityEvent; if (that.message == 100) { // message 为100时进行跳转计算页面 router.push({ uri: "pages/calculate/calculate" }) that.unsubscribe(); // 取消订阅 that.isShow = false; // 隐藏进度条 } }) } ``` 2. java端在ServiceAbility中对订阅请求进行处理,在内部类MyRemote的onRemoteRequest方法中根据code参数来判断请求类型进行相应处理。 ```java case ACTION_MESSAGE_CODE_PLUS_SUB: { go = true; // 开启可以下载状态 remoteObjectHandler = data.readRemoteObject(); // 获取请求参数对象 String zsonStr = data.readString(); // 获取参数字符串 try { param = ZSONObject.stringToClass(zsonStr, RequestParam.class); // 字符串对象转成RequestParam实例 } catch (RuntimeException e) { } startNotify(param); // 给js端发送信息 Map zsonResult = new HashMap();// 返回结果,关键字段应与Js方协商 zsonResult.put("code", SUCCESS); reply.writeString(ZSONObject.toZSONString(zsonResult)); // map 对象转成json字符串,并返回给js端 return true; } ``` 3. java端开启线程,按照5*3 每15毫秒的频率返回数据给js端。这里java发送给js的数据,js端会通过订阅java pa的回调函数中而实时获取到。 ```java /** * 开启线程,按照5*3 每15毫秒的频率返回数据给js端。这里java发送给js的数据, * js端会通过订阅java pa的回调函数中而实时获取到 */ public void startNotify(RequestParam param) { number = param.getFirstNum(); // 获取当前进度值从请求中获取 new Thread(() -> { // 开启线程 while (go) { try { Thread.sleep(5 * 3); // 线程睡眠15毫秒后继续往下执行 MessageParcel data = MessageParcel.obtain(); // 创建索引为0的空MessageParcel对象 MessageParcel reply = MessageParcel.obtain(); zsonEvent.put("abilityEvent", number++); if (number == 101) { // number超过100 go状态设为false 下载结束 go = false; } data.writeString(ZSONObject.toZSONString(zsonEvent)); // 数据存到MessageParcel载体 remoteObjectHandler.sendRequest(100, data, reply, option); // 发送 reply.reclaim(); // 回收 data.reclaim(); } catch (RemoteException | InterruptedException e) { break; } } }).start(); } ``` 4. js页面点击取消按钮,取消订阅模式, java端停止返回数据。 js端代码如下: ```javascript /** * 请求取消订阅, java端停止返回数据 */ unsubscribe: async function() { var action = {}; action.bundleName = 'com.example.javajscommunication'; // Ability的包名称,需要与PA端匹配,区分大小写 action.abilityName = 'com.example.javajscommunication.ServiceAbility'; // Ability名称,需要与PA端匹配,区分大小写 action.messageCode = ACTION_MESSAGE_CODE_PLUS_UNSUB; // Ability操作码(操作码定义PA的业务功能,需要与PA端约定) action.abilityType = ABILITY_TYPE_EXTERNAL; // Ability类型,对应PA端不同的实现方式 action.syncOption = ACTION_SYNC; // PA侧请求消息处理同步/异步选项 0:同步方式,默认方式。 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代码如下: ```java case ACTION_MESSAGE_CODE_PLUS_UNSUB: { go = false; // 停止方法startNotify中的while循环,停止往js端发送消息 Map zsonResult = new HashMap(); zsonResult.put("code", SUCCESS); reply.writeString(ZSONObject.toZSONString(zsonResult)); // 响应js端 return true; } ``` #### 五、调用PA解读 1. 获取input输入的值,作为js端传递过去的值。 ```javascript /** * 取传过去的第一个值 */ numOne (e){ this.numOne = e.value }, /** * 获取传过去的第二个值 */ numTwo (e){ this.numTwo = e.value } ``` 2. 点击求积按钮 发送调用模式的请求。 ```javascript calculate: async function() { var actionData = {}; // key值对应PA端的RequestParam类的成员字段 actionData.firstNum = this.numOne; actionData.secondNum = this.numTwo; var action = {}; action.bundleName = 'com.example.javajscommunication'; // Ability的包名称,需要与PA端匹配,区分大小写 action.abilityName = 'com.example.javajscommunication.ServiceAbility'; // Ability名称,需要与PA端匹配,区分大小写 action.messageCode = ACTION_MESSAGE_CODE_PLUS; // Ability操作码(操作码定义PA的业务功能,需要与PA端约定) action.data = actionData; // 发送到Ability的数据,数据字段名称需要与PA端约定 action.abilityType = ABILITY_TYPE_EXTERNAL; // Ability类型,对应PA端不同的实现方式 action.syncOption = ACTION_SYNC; // PA侧请求消息处理同步/异步选项 0:同步方式,默认方式。 1:异步方式 var result = await FeatureAbility.callAbility(action); var ret = JSON.parse(result); if (ret.code == 0) { this.message = 'java端传回的数据为:' + JSON.stringify(ret.abilityResult); } else { this.message = 'java端传回的数据报错' + JSON.stringify(ret.code); } }, ``` 3. java端在ServiceAbility中对订阅请求进行处理,在内部类MyRemote的onRemoteRequest方法中根据code参数来判断请求类型进行相应处理。这里java发送给js的数据,js端会通过调用java pa的结果而获取到。 ```java case ACTION_MESSAGE_CODE_PLUS: { String zsonStr = data.readString(); // 获取传入参数的字符串 RequestParam param = new RequestParam(); try { param = ZSONObject.stringToClass(zsonStr, RequestParam.class); // 字符串对象转成RequestParam实例 } catch (RuntimeException e) { } // 返回结果仅支持可序列化的Object类型 Map zsonResult = new HashMap<>(); zsonResult.put("code", SUCCESS); zsonResult.put("abilityResult", param.getFirstNum() + " * " + param.getSecondNum() + " = " + (param.getFirstNum() * param.getSecondNum())); reply.writeString(ZSONObject.toZSONString(zsonResult)); // 数据返回给js端 return true; } ``` 4. 返回到前一个页面,这里在页面js中import router from '@system.router',然后利用router对象的相关方法返回。 ```javascript back(){ router.back() // 返回到前一个页面 } ``` #### 六、代码参考 [https://gitee.com/chinasoft6_ohos/java-js-communication](https://gitee.com/chinasoft6_ohos/java-js-communication) 作者 :晋国晨