鴻蒙OS JS FA如何調(diào)用PA

2020-09-18 14:03 更新

JS UI 框架提供了 JS FA(Feature Ability)調(diào)用 Java PA(Particle Ability)的機(jī)制,該機(jī)制提供了一種通道來傳遞方法調(diào)用、數(shù)據(jù)返回以及訂閱事件上報。

當(dāng)前提供 Ability 和 Internal Ability 兩種調(diào)用方式,開發(fā)者可以根據(jù)業(yè)務(wù)場景選擇合適的調(diào)用方式進(jìn)行開發(fā)。

  • Ability:擁有獨立的 Ability 生命周期,F(xiàn)A 使用遠(yuǎn)端進(jìn)程通信拉起并請求 PA 服務(wù),適用于基本服務(wù)供多 FA 調(diào)用或者服務(wù)在后臺獨立運(yùn)行的場景。

  • Internal Ability:與 FA 共進(jìn)程,采用內(nèi)部函數(shù)調(diào)用的方式和 FA 進(jìn)行通信,適用于對服務(wù)響應(yīng)時延要求較高的場景。該方式下 PA 不支持其他 FA 訪問調(diào)用。

JS 端與 Java 端通過 bundleName 和 abilityName 來進(jìn)行關(guān)聯(lián)。在系統(tǒng)收到 JS 調(diào)用請求后,根據(jù)開發(fā)者在 JS 接口中設(shè)置的參數(shù)來選擇對應(yīng)的處理方式。開發(fā)者在 onRemoteRequest() 中實現(xiàn) PA 提供的業(yè)務(wù)邏輯。詳細(xì)信息請參考 JS FA調(diào)用Java PA機(jī)制。

FA 調(diào)用 PA 接口

FA 端提供以下三個 JS 接口:

  • FeatureAbility.callAbility(OBJECT):調(diào)用 PA 能力。
  • FeatureAbility.subscribeAbilityEvent(OBJECT, Function):訂閱 PA 能力。
  • FeatureAbility.unsubscribeAbilityEvent(OBJECT):取消訂閱 PA 能力。

PA 端提供以下兩類接口:

  • boolean IRemoteObject.onRemoteRequest(int code, MessageParcel data, MessageParcel reply, MessageOption option):Ability 調(diào)用方式,F(xiàn)A 使用遠(yuǎn)端進(jìn)程通信拉起并請求PA服務(wù)。
  • boolean AceInternalAbility.AceInternalAbilityHandler.onRemoteRequest(int code, MessageParcel data, MessageParcel reply, MessageOption option):Internal Ability 調(diào)用方式,采用內(nèi)部函數(shù)調(diào)用的方式和 FA 進(jìn)行通信。

FA 調(diào)用 PA 常見問題

  • callAbility返回報錯:"Internal ability not register."

返回該錯誤說明 JS 接口調(diào)用請求未在系統(tǒng)中找到對應(yīng)的 InternalAbilityHandler 進(jìn)行處理,因此需要檢查以下幾點是否正確執(zhí)行:

  1. 在 AceAbility 繼承類中對 AceInternalAbility 繼承類執(zhí)行了 register 方法,具體注冊可參考 Internal Ability 的示例代碼。
  2. JS 側(cè)填寫的 bundleName 和 abilityName 與 AceInternalAbility 繼承類構(gòu)造函數(shù)中填寫的名稱保持相同,大小寫敏感。
  3. 檢查 JS 端填寫的 abilityType(0:Ability; 1:Internal Ability),確保沒有將 Ability 誤填寫為 Internal Ability 方式。

Ability 和 Internal Ability 是兩種不同的 FA 調(diào)用 PA 的方式。 [表1]列舉了在開發(fā)時各方面的差異,供開發(fā)者參考,避免開發(fā)時將兩者混淆使用:

差異項 Ability InternalAbility
JS端(abilityType) 0 1
是否需要在 config.json 的 abilities 中為 PA 添加聲明 需要(有獨立的生命周期) 不需要(和FA共生命周期)
是否需要在FA中注冊 不需要 需要
繼承的類 ohos.aafwk.ability.Ability ohos.ace.ability.AceInternalAbility
是否允許被其他FA訪問調(diào)用

  • FeatureAbility.callAbility中syncOption參數(shù)說明:

  • 對于 JS FA 側(cè),返回的結(jié)果都是 Promise 對象,因此無論該參數(shù)取何值,都采用異步方式等待 PA 側(cè)響應(yīng)。
  • 對于 JAVA PA 側(cè),在 Internal Ability 方式下收到 FA 的請求后,根據(jù)該參數(shù)的取值來選擇:通過同步的方式獲取結(jié)果后返回;或者異步執(zhí)行 PA 邏輯,獲取結(jié)果后使用 remoteObject.sendRequest 的方式將結(jié)果返回 FA。

  • 使用 await 方式調(diào)用時 IDE 編譯報錯,需引入 babel-runtime/regenerator,具體請參見接口通用規(guī)則。

示例參考

  • FA JavaScript端

  1. // abilityType: 0-Ability; 1-Internal Ability
  2. const ABILITY_TYPE_EXTERNAL = 0;
  3. const ABILITY_TYPE_INTERNAL = 1;
  4. // syncOption(Optional, default sync): 0-Sync; 1-Async
  5. const ACTION_SYNC = 0;
  6. const ACTION_ASYNC = 1;
  7. const ACTION_MESSAGE_CODE_PLUS = 1001;
  8. export default {
  9. plus: async function() {
  10. var actionData = {};
  11. actionData.firstNum = 1024;
  12. actionData.secondNum = 2048;
  13. var action = {};
  14. action.bundleName = 'com.huawei.hiaceservice';
  15. action.abilityName = 'CalcServiceAbility';
  16. action.messageCode = ACTION_MESSAGE_CODE_PLUS;
  17. action.data = actionData;
  18. action.abilityType = ABILITY_TYPE_EXTERNAL;
  19. action.syncOption = ACTION_SYNC;
  20. var result = await FeatureAbility.callAbility(action);
  21. var ret = JSON.parse(result);
  22. if (ret.code && ret.code == 0) {
  23. console.info('plus result is:' + JSON.stringify(ret.abilityResult));
  24. } else {
  25. if (ret.code) {
  26. console.error('plus error code:' + JSON.stringify(ret.code));
  27. } else {
  28. console.error('plus error undefined.');
  29. }
  30. }
  31. }
  32. }

  • PA 端(Ability 方式)

功能代碼實現(xiàn):

CalcServiceAbility.java

  1. // ohos相關(guān)接口包
  2. import ohos.aafwk.ability.Ability;
  3. import ohos.aafwk.content.Intent;
  4. import ohos.rpc.IRemoteBroker;
  5. import ohos.rpc.IRemoteObject;
  6. import ohos.rpc.RemoteObject;
  7. import ohos.rpc.MessageParcel;
  8. import ohos.rpc.MessageOption;
  9. import ohos.utils.zson.ZSONObject;
  10. import java.util.HashMap;
  11. import java.util.Map;
  12. public class CalcServiceAbility extends Ability {
  13. private static final String TAG = "CalcServiceAbility";
  14. private MyRemote remote = new MyRemote();
  15. // FA在請求PA服務(wù)時會調(diào)用AbilityconnectAbility連接PA,連接成功后,需要在onConnect返回一個remote對象,供FA向PA發(fā)送消息
  16. @Override
  17. protected IRemoteObject onConnect(Intent intent) {
  18. super.onConnect(intent);
  19. return remote.asObject();
  20. }
  21. class MyRemote extends RemoteObject implements IRemoteBroker {
  22. private static final int ERROR = -1;
  23. private static final int SUCCESS = 0;
  24. private static final int PLUS = 1001;
  25. MyRemote() {
  26. super("MyService_MyRemote");
  27. }
  28. @Override
  29. public boolean onRemoteRequest(int code, MessageParcel data, MessageParcel reply, MessageOption option) {
  30. switch (code) {
  31. case PLUS: {
  32. String zsonStr = data.readString();
  33. RequestParam param = ZSONObject.stringToClass(zsonStr, RequestParam.class);
  34. // 返回結(jié)果僅支持可序列化的Object類型
  35. Map<String, Object> zsonResult = new HashMap<String, Object>();
  36. zsonResult.put("code", SUCCESS);
  37. zsonResult.put("abilityResult", param.getFirstNum() + param.getSecondNum());
  38. reply.writeString(ZSONObject.toZSONString(zsonResult));
  39. break;
  40. }
  41. default: {
  42. Map<String, Object> zsonResult = new HashMap<String, Object>();
  43. zsonResult.put("abilityError", ERROR);
  44. reply.writeString(ZSONObject.toZSONString(zsonResult));
  45. return false;
  46. }
  47. }
  48. return true;
  49. }
  50. @Override
  51. public IRemoteObject asObject() {
  52. return this;
  53. }
  54. }
  55. }

請求參數(shù)代碼:

RequestParam.java

  1. public class RequestParam {
  2. private int firstNum;
  3. private int secondNum;
  4. public int getFirstNum() {
  5. return firstNum;
  6. }
  7. public void setFirstNum(int firstNum) {
  8. this.firstNum = firstNum;
  9. }
  10. public int getSecondNum() {
  11. return secondNum;
  12. }
  13. public void setSecondNum(int secondNum) {
  14. this.secondNum = secondNum;
  15. }
  16. }

  • PA 端(Internal Ability方式)

功能代碼實現(xiàn):

CalcInternalAbility.java

  1. // ohos相關(guān)接口包
  2. import ohos.ace.ability.AceInternalAbility;
  3. import ohos.app.AbilityContext;
  4. import ohos.rpc.IRemoteObject;
  5. import ohos.rpc.MessageOption;
  6. import ohos.rpc.MessageParcel;
  7. import ohos.rpc.RemoteException;
  8. import ohos.utils.zson.ZSONObject;
  9. import java.util.HashMap;
  10. import java.util.Map;
  11. public class CalcInternalAbility extends AceInternalAbility {
  12. private static final String TAG = CalcInternalAbility.class.getSimpleName();
  13. private static final String BUNDLE_NAME = "com.huawei.hiaceservice";
  14. private static final String ABILITY_NAME = "CalcInternalAbility";
  15. private static final int ERROR = -1;
  16. private static final int SUCCESS = 0;
  17. private static final int PLUS = 1001;
  18. private static CalcInternalAbility instance;
  19. private AbilityContext abilityContext;
  20. // 如果多個Ability實例都需要注冊當(dāng)前InternalAbility實例,需要更改構(gòu)造函數(shù),設(shè)定自己的bundleName和abilityName
  21. public CalcInternalAbility() {
  22. super(BUNDLE_NAME, ABILITY_NAME);
  23. }
  24. public boolean onRemoteRequest(int code, MessageParcel data, MessageParcel reply, MessageOption option) {
  25. switch (code) {
  26. case PLUS: {
  27. String zsonStr = data.readString();
  28. RequestParam param = ZSONObject.stringToClass(zsonStr, RequestParam.class);
  29. // 返回結(jié)果當(dāng)前僅支持String,對于復(fù)雜結(jié)構(gòu)可以序列化為ZSON字符串上報
  30. Map<String, Object> zsonResult = new HashMap<String, Object>();
  31. zsonResult.put("code", SUCCESS);
  32. zsonResult.put("abilityResult", param.getFirstNum() + param.getSecondNum());
  33. // SYNC
  34. if (option.getFlags() == MessageOption.TF_SYNC) {
  35. reply.writeString(ZSONObject.toZSONString(zsonResult));
  36. } else {
  37. // ASYNC
  38. MessageParcel reponseData = MessageParcel.obtain();
  39. reponseData.writeString(ZSONObject.toZSONString(zsonResult));
  40. IRemoteObject remoteReply = reply.readRemoteObject();
  41. try {
  42. remoteReply.sendRequest(0, reponseData, MessageParcel.obtain(), new MessageOption());
  43. reponseData.reclaim();
  44. } catch (RemoteException exception) {
  45. return false;
  46. }
  47. }
  48. break;
  49. }
  50. default: {
  51. Map<String, Object> zsonResult = new HashMap<String, Object>();
  52. zsonResult.put("abilityError", ERROR);
  53. reply.writeString(ZSONObject.toZSONString(zsonResult));
  54. return false;
  55. }
  56. }
  57. return true;
  58. }
  59. /**
  60. * Internal ability registration.
  61. */
  62. public static void register(AbilityContext abilityContext) {
  63. instance = new CalcInternalAbility();
  64. instance.onRegister(abilityContext);
  65. }
  66. private void onRegister(AbilityContext abilityContext) {
  67. this.abilityContext = abilityContext;
  68. this.setInternalAbilityHandler((code, data, reply, option) -> {
  69. return this.onRemoteRequest(code, data, reply, option);
  70. });
  71. }
  72. /**
  73. * Internal ability deregistration.
  74. */
  75. public static void deregister() {
  76. instance.onDeregister();
  77. }
  78. private void onDeregister() {
  79. abilityContext = null;
  80. this.setInternalAbilityHandler(null);
  81. }
  82. }

Internal Ability 注冊:修改繼承 AceAbility 工程中的代碼

  1. public class HiAceInternalAbility extends AceAbility {
  2. @Override
  3. public void onStart(Intent intent) {
  4. super.onStart(intent);
  5. // 注冊
  6. CalcInternalAbility.register(this);
  7. ...
  8. }
  9. @Override
  10. public void onStop() {
  11. // 去注冊
  12. CalcInternalAbility.deregister();
  13. super.onStop();
  14. }
  15. }
以上內(nèi)容是否對您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號
微信公眾號

編程獅公眾號