鴻蒙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ī)制提供了一種通道來(lái)傳遞方法調(diào)用、數(shù)據(jù)返回以及訂閱事件上報(bào)。

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

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

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

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

FA 調(diào)用 PA 接口

FA 端提供以下三個(gè) 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)程通信拉起并請(qǐng)求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 常見問(wèn)題

  • callAbility返回報(bào)錯(cuò):"Internal ability not register."

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

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

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

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

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

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

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

示例參考

  • FA JavaScript端

  // abilityType: 0-Ability; 1-Internal Ability
  const ABILITY_TYPE_EXTERNAL = 0;
  const ABILITY_TYPE_INTERNAL = 1;
  // syncOption(Optional, default sync): 0-Sync; 1-Async
  const ACTION_SYNC = 0;
  const ACTION_ASYNC = 1;
  const ACTION_MESSAGE_CODE_PLUS = 1001;
  export default {
    plus: async function() {
      var actionData = {};
      actionData.firstNum = 1024;
      actionData.secondNum = 2048;

   
      var action = {};
      action.bundleName = 'com.huawei.hiaceservice';
      action.abilityName = 'CalcServiceAbility';
      action.messageCode = ACTION_MESSAGE_CODE_PLUS;
      action.data = actionData;
      action.abilityType = ABILITY_TYPE_EXTERNAL;
      action.syncOption = ACTION_SYNC;

   
      var result = await FeatureAbility.callAbility(action);
      var ret = JSON.parse(result);
      if (ret.code && ret.code == 0) {
        console.info('plus result is:' + JSON.stringify(ret.abilityResult));
      } else {
        if (ret.code) {
          console.error('plus error code:' + JSON.stringify(ret.code));
        } else {
          console.error('plus error undefined.');
        }
      }
    }
  }

  • PA 端(Ability 方式)

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

CalcServiceAbility.java

  // ohos相關(guān)接口包
  import ohos.aafwk.ability.Ability;
  import ohos.aafwk.content.Intent;
  import ohos.rpc.IRemoteBroker;
  import ohos.rpc.IRemoteObject;
  import ohos.rpc.RemoteObject;
  import ohos.rpc.MessageParcel;
  import ohos.rpc.MessageOption;
  import ohos.utils.zson.ZSONObject;

   
  import java.util.HashMap;
  import java.util.Map;

   
  public class CalcServiceAbility extends Ability {
      private static final String TAG = "CalcServiceAbility";
      private MyRemote remote = new MyRemote();
      // FA在請(qǐng)求PA服務(wù)時(shí)會(huì)調(diào)用AbilityconnectAbility連接PA,連接成功后,需要在onConnect返回一個(gè)remote對(duì)象,供FA向PA發(fā)送消息
      @Override
      protected IRemoteObject onConnect(Intent intent) {
          super.onConnect(intent);
          return remote.asObject();
      }
      class MyRemote extends RemoteObject implements IRemoteBroker {
          private static final int ERROR = -1;
          private static final int SUCCESS = 0;
          private static final int PLUS = 1001;   

   
          MyRemote() {
              super("MyService_MyRemote");
          }

   
          @Override
          public boolean onRemoteRequest(int code, MessageParcel data, MessageParcel reply, MessageOption option) {
              switch (code) {
                  case PLUS: {
                      String zsonStr = data.readString();
                      RequestParam param = ZSONObject.stringToClass(zsonStr, RequestParam.class);

                      
                      // 返回結(jié)果僅支持可序列化的Object類型
                      Map<String, Object> zsonResult = new HashMap<String, Object>();
                      zsonResult.put("code", SUCCESS);
                      zsonResult.put("abilityResult", param.getFirstNum() + param.getSecondNum());
                      reply.writeString(ZSONObject.toZSONString(zsonResult));
                      break;
                  }
                  default: {
                      Map<String, Object> zsonResult = new HashMap<String, Object>();
                      zsonResult.put("abilityError", ERROR);
                      reply.writeString(ZSONObject.toZSONString(zsonResult));
                      return false;
                  }
              }
              return true;
          }

   
          @Override
          public IRemoteObject asObject() {
              return this;
          }
      }
  }

請(qǐng)求參數(shù)代碼:

RequestParam.java

  public class RequestParam {
      private int firstNum;
      private int secondNum;

   
      public int getFirstNum() {
          return firstNum;
      }

   
      public void setFirstNum(int firstNum) {
          this.firstNum = firstNum;
      }

   
      public int getSecondNum() {
          return secondNum;
      }

   
      public void setSecondNum(int secondNum) {
          this.secondNum = secondNum;
      }
  }

  • PA 端(Internal Ability方式)

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

CalcInternalAbility.java

  // ohos相關(guān)接口包
  import ohos.ace.ability.AceInternalAbility;
  import ohos.app.AbilityContext;
  import ohos.rpc.IRemoteObject;
  import ohos.rpc.MessageOption;
  import ohos.rpc.MessageParcel;
  import ohos.rpc.RemoteException;
  import ohos.utils.zson.ZSONObject;

   
  import java.util.HashMap;
  import java.util.Map;

   
  public class CalcInternalAbility extends AceInternalAbility {
      private static final String TAG = CalcInternalAbility.class.getSimpleName();
      private static final String BUNDLE_NAME = "com.huawei.hiaceservice";
      private static final String ABILITY_NAME = "CalcInternalAbility";
      private static final int ERROR = -1;
      private static final int SUCCESS = 0;
      private static final int PLUS = 1001;

   
      private static CalcInternalAbility instance;
      private AbilityContext abilityContext;

   
      // 如果多個(gè)Ability實(shí)例都需要注冊(cè)當(dāng)前InternalAbility實(shí)例,需要更改構(gòu)造函數(shù),設(shè)定自己的bundleName和abilityName
      public CalcInternalAbility() {
          super(BUNDLE_NAME, ABILITY_NAME);
      }

   
      public boolean onRemoteRequest(int code, MessageParcel data, MessageParcel reply, MessageOption option) {
          switch (code) {
              case PLUS: {
                  String zsonStr = data.readString();
                  RequestParam param = ZSONObject.stringToClass(zsonStr, RequestParam.class);
                  // 返回結(jié)果當(dāng)前僅支持String,對(duì)于復(fù)雜結(jié)構(gòu)可以序列化為ZSON字符串上報(bào)
                  Map<String, Object> zsonResult = new HashMap<String, Object>();
                  zsonResult.put("code", SUCCESS);
                  zsonResult.put("abilityResult", param.getFirstNum() + param.getSecondNum());
                  // SYNC
                  if (option.getFlags() == MessageOption.TF_SYNC) {
                      reply.writeString(ZSONObject.toZSONString(zsonResult));
                  } else {
                      // ASYNC
                      MessageParcel reponseData = MessageParcel.obtain();
                      reponseData.writeString(ZSONObject.toZSONString(zsonResult));
                      IRemoteObject remoteReply = reply.readRemoteObject();
                      try {
                          remoteReply.sendRequest(0, reponseData, MessageParcel.obtain(), new MessageOption());
                          reponseData.reclaim();
                      } catch (RemoteException exception) {
                          return false;
                      }
                  }
                  break;
              }
              default: {
                  Map<String, Object> zsonResult = new HashMap<String, Object>();
                  zsonResult.put("abilityError", ERROR);
                  reply.writeString(ZSONObject.toZSONString(zsonResult));
                  return false;
              }
          }
          return true;
      }

   
      /**
       * Internal ability registration.
       */
      public static void register(AbilityContext abilityContext) {
          instance = new CalcInternalAbility();
          instance.onRegister(abilityContext);
      }

   
      private void onRegister(AbilityContext abilityContext) {
          this.abilityContext = abilityContext;
          this.setInternalAbilityHandler((code, data, reply, option) -> {
              return this.onRemoteRequest(code, data, reply, option);
          });
      }

   
      /**
       * Internal ability deregistration.
       */
      public static void deregister() {
          instance.onDeregister();
      }

   
      private void onDeregister() {
          abilityContext = null;
          this.setInternalAbilityHandler(null);
      }
  }

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

  public class HiAceInternalAbility extends AceAbility {

   
      @Override
      public void onStart(Intent intent) {
          super.onStart(intent);
          // 注冊(cè)
          CalcInternalAbility.register(this);
          ...
      }
      @Override 
      public void onStop() {
          // 去注冊(cè)
          CalcInternalAbility.deregister();     
          super.onStop();
      }
  }
以上內(nèi)容是否對(duì)您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號(hào)
微信公眾號(hào)

編程獅公眾號(hào)