codecamp

鸿蒙OS JS FA如何调用PA

JS UI 框架提供了 JS FA(Feature Ability)调用 Java PA(Particle Ability)的机制,该机制提供了一种通道来传递方法调用、数据返回以及订阅事件上报。

当前提供 Ability 和 Internal Ability 两种调用方式,开发者可以根据业务场景选择合适的调用方式进行开发。

  • Ability:拥有独立的 Ability 生命周期,FA 使用远端进程通信拉起并请求 PA 服务,适用于基本服务供多 FA 调用或者服务在后台独立运行的场景。

  • Internal Ability:与 FA 共进程,采用内部函数调用的方式和 FA 进行通信,适用于对服务响应时延要求较高的场景。该方式下 PA 不支持其他 FA 访问调用。

JS 端与 Java 端通过 bundleName 和 abilityName 来进行关联。在系统收到 JS 调用请求后,根据开发者在 JS 接口中设置的参数来选择对应的处理方式。开发者在 onRemoteRequest() 中实现 PA 提供的业务逻辑。详细信息请参考 JS FA调用Java PA机制

FA 调用 PA 接口

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

  • FeatureAbility.callAbility(OBJECT):调用 PA 能力。
  • FeatureAbility.subscribeAbilityEvent(OBJECT, Function):订阅 PA 能力。
  • FeatureAbility.unsubscribeAbilityEvent(OBJECT):取消订阅 PA 能力。

PA 端提供以下两类接口:

  • boolean IRemoteObject.onRemoteRequest(int code, MessageParcel data, MessageParcel reply, MessageOption option):Ability 调用方式,FA 使用远端进程通信拉起并请求PA服务。
  • boolean AceInternalAbility.AceInternalAbilityHandler.onRemoteRequest(int code, MessageParcel data, MessageParcel reply, MessageOption option):Internal Ability 调用方式,采用内部函数调用的方式和 FA 进行通信。

FA 调用 PA 常见问题

  • callAbility返回报错:"Internal ability not register."

返回该错误说明 JS 接口调用请求未在系统中找到对应的 InternalAbilityHandler 进行处理,因此需要检查以下几点是否正确执行:

  1. 在 AceAbility 继承类中对 AceInternalAbility 继承类执行了 register 方法,具体注册可参考 Internal Ability 的示例代码。
  2. JS 侧填写的 bundleName 和 abilityName 与 AceInternalAbility 继承类构造函数中填写的名称保持相同,大小写敏感。
  3. 检查 JS 端填写的 abilityType(0:Ability; 1:Internal Ability),确保没有将 Ability 误填写为 Internal Ability 方式。

Ability 和 Internal Ability 是两种不同的 FA 调用 PA 的方式。 [表1]列举了在开发时各方面的差异,供开发者参考,避免开发时将两者混淆使用:

差异项 Ability InternalAbility
JS端(abilityType) 0 1
是否需要在 config.json 的 abilities 中为 PA 添加声明 需要(有独立的生命周期) 不需要(和FA共生命周期)
是否需要在FA中注册 不需要 需要
继承的类 ohos.aafwk.ability.Ability ohos.ace.ability.AceInternalAbility
是否允许被其他FA访问调用

  • FeatureAbility.callAbility中syncOption参数说明:

  • 对于 JS FA 侧,返回的结果都是 Promise 对象,因此无论该参数取何值,都采用异步方式等待 PA 侧响应。
  • 对于 JAVA PA 侧,在 Internal Ability 方式下收到 FA 的请求后,根据该参数的取值来选择:通过同步的方式获取结果后返回;或者异步执行 PA 逻辑,获取结果后使用 remoteObject.sendRequest 的方式将结果返回 FA。

  • 使用 await 方式调用时 IDE 编译报错,需引入 babel-runtime/regenerator,具体请参见接口通用规则

示例参考

  • 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 方式)

功能代码实现:

CalcServiceAbility.java

  // ohos相关接口包
  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在请求PA服务时会调用AbilityconnectAbility连接PA,连接成功后,需要在onConnect返回一个remote对象,供FA向PA发送消息
      @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);

                      
                      // 返回结果仅支持可序列化的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;
          }
      }
  }

请求参数代码:

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方式)

功能代码实现:

CalcInternalAbility.java

  // ohos相关接口包
  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;

   
      // 如果多个Ability实例都需要注册当前InternalAbility实例,需要更改构造函数,设定自己的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);
                  // 返回结果当前仅支持String,对于复杂结构可以序列化为ZSON字符串上报
                  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 注册:修改继承 AceAbility 工程中的代码

  public class HiAceInternalAbility extends AceAbility {

   
      @Override
      public void onStart(Intent intent) {
          super.onStart(intent);
          // 注册
          CalcInternalAbility.register(this);
          ...
      }
      @Override 
      public void onStop() {
          // 去注册
          CalcInternalAbility.deregister();     
          super.onStop();
      }
  }
鸿蒙OS 自定义组件
鸿蒙OS 多模输入概述
温馨提示
下载编程狮App,免费阅读超1000+编程语言教程
取消
确定
目录

鸿蒙OS 开发

鸿蒙OS 术语

鸿蒙OS Java API参考

鸿蒙OS ohos.aafwk.ability

鸿蒙OS ohos.aafwk.abilityjet.activedata

鸿蒙OS ohos.aafwk.content

鸿蒙OS java.lang

鸿蒙OS java.Util

鸿蒙OS java.Util class

鸿蒙OS ohos.data.dataability

鸿蒙OS ohos.data.dataability class

鸿蒙OS ohos.agp.components

鸿蒙OS ohos.agp.components interface

鸿蒙OS ohos.agp.components class

鸿蒙OS ohos.global.configuration

鸿蒙OS java.io

鸿蒙OS ohos.data.resultset

鸿蒙OS ohos.data.resultset interface

关闭

MIP.setData({ 'pageTheme' : getCookie('pageTheme') || {'day':true, 'night':false}, 'pageFontSize' : getCookie('pageFontSize') || 20 }); MIP.watch('pageTheme', function(newValue){ setCookie('pageTheme', JSON.stringify(newValue)) }); MIP.watch('pageFontSize', function(newValue){ setCookie('pageFontSize', newValue) }); function setCookie(name, value){ var days = 1; var exp = new Date(); exp.setTime(exp.getTime() + days*24*60*60*1000); document.cookie = name + '=' + value + ';expires=' + exp.toUTCString(); } function getCookie(name){ var reg = new RegExp('(^| )' + name + '=([^;]*)(;|$)'); return document.cookie.match(reg) ? JSON.parse(document.cookie.match(reg)[2]) : null; }