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端提供以下两类接口:

  • IRemoteObject.onRemoteRequest(int, MessageParcel, MessageParcel, MessageOption):Ability调用方式,FA使用远端进程通信拉起并请求PA服务。
  • AceInternalAbility.AceInternalAbilityHandler.onRemoteRequest(int, MessageParcel, MessageParcel, MessageOption):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),确保没有将AbilityType缺省或误填写为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,具体请参见接口通用规则

示例参考

JS端调用FeatureAbility接口,传入两个Number参数,Java端接收后返回两个数的和。

  • FA JavaScript端

    使用Internal Ability方式时,需要将对应的action.abilityType值改为ABILITY_TYPE_INTERNAL。

    // abilityType: 0-Ability; 1-Internal Abilityconst ABILITY_TYPE_EXTERNAL = 0;const ABILITY_TYPE_INTERNAL = 1;// syncOption(Optional, default sync): 0-Sync; 1-Asyncconst 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.example.hiaceservice';    action.abilityName = 'com.example.hiaceservice.ComputeServiceAbility';    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 == 0) {      console.info('plus result is:' + JSON.stringify(ret.abilityResult));    } else {      console.error('plus error code:' + JSON.stringify(ret.code));    }  }}
    
  • PA端(Ability方式)

    功能代码实现:

    在java目录下新建一个Service Ability,文件命名为ComputeServiceAbility.java

    package com.example.hiaceservice;
    // ohos相关接口包import ohos.aafwk.ability.Ability;import ohos.aafwk.content.Intent;import ohos.hiviewdfx.HiLog;import ohos.hiviewdfx.HiLogLabel;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 ComputeServiceAbility extends Ability {  // 定义日志标签  private static final HiLogLabel LABEL = new HiLogLabel(HiLog.LOG_APP, 0, "MY_TAG");
      private MyRemote remote = new MyRemote();  // FA在请求PA服务时会调用Ability.connectAbility连接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 SUCCESS = 0;    private static final int ERROR = 1;    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 dataStr = data.readString();          RequestParam param = new RequestParam();          try {                  param = ZSONObject.stringToClass(dataStr, RequestParam.class);          } catch (RuntimeException e) {                  HiLog.error(LABEL, "convert failed.");          }                              // 返回结果当前仅支持String,对于复杂结构可以序列化为ZSON字符串上报          Map<String, Object> result = new HashMap<String, Object>();          result.put("code", SUCCESS);          result.put("abilityResult", param.getFirstNum() + param.getSecondNum());          reply.writeString(ZSONObject.toZSONString(result));          break;        }        default: {          Map<String, Object> result = new HashMap<String, Object>();          result.put("abilityError", ERROR);          reply.writeString(ZSONObject.toZSONString(result));          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方式)

    功能代码实现:

    在java目录下新建一个Service Ability,文件命名为ComputeInternalAbility.java

    package com.example.hiaceservice;
    // ohos相关接口包import ohos.ace.ability.AceInternalAbility;import ohos.app.AbilityContext;import ohos.hiviewdfx.HiLog;import ohos.hiviewdfx.HiLogLabel;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 ComputeInternalAbility extends AceInternalAbility {  private static final String BUNDLE_NAME = "com.example.hiaceservice";  private static final String ABILITY_NAME = "com.example.hiaceservice.ComputeInternalAbility";  private static final int SUCCESS = 0;  private static final int ERROR = 1;  private static final int PLUS = 1001;  // 定义日志标签  private static final HiLogLabel LABEL = new HiLogLabel(HiLog.LOG_APP, 0, "MY_TAG");
      private static ComputeInternalAbility instance;  private AbilityContext abilityContext;
      // 如果多个Ability实例都需要注册当前InternalAbility实例,需要更改构造函数,设定自己的bundleName和abilityName  public ComputeInternalAbility() {    super(BUNDLE_NAME, ABILITY_NAME);  }
      public boolean onRemoteRequest(int code, MessageParcel data, MessageParcel reply, MessageOption option) {    switch (code) {      case PLUS: {        String dataStr = data.readString();        RequestParam param = new RequestParam();        try {                param = ZSONObject.stringToClass(dataStr, RequestParam.class);        } catch (RuntimeException e) {                HiLog.error(LABEL, "convert failed.");        }
            // 返回结果当前仅支持String,对于复杂结构可以序列化为ZSON字符串上报        Map<String, Object> result = new HashMap<String, Object>();        result.put("code", SUCCESS);        result.put("abilityResult", param.getFirstNum() + param.getSecondNum());        // SYNC        if (option.getFlags() == MessageOption.TF_SYNC) {          reply.writeString(ZSONObject.toZSONString(result));        } else {          // ASYNC          MessageParcel responseData = MessageParcel.obtain();          responseData.writeString(ZSONObject.toZSONString(result));          IRemoteObject remoteReply = reply.readRemoteObject();          try {            remoteReply.sendRequest(0, responseData, MessageParcel.obtain(), new MessageOption());          } catch (RemoteException exception) {              return false;          } finally {              responseData.reclaim();          }        }        break;      }      default: {        Map<String, Object> result = new HashMap<String, Object>();        result.put("abilityError", ERROR);        reply.writeString(ZSONObject.toZSONString(result));        return false;      }    }    return true;  }
      /**  * Internal ability 注册接口。  */  public static void register(AbilityContext abilityContext) {    instance = new ComputeInternalAbility();    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 注销接口。   */  public static void unregister() {    instance.onUnregister();  }
      private void onUnregister() {    abilityContext = null;    this.setInternalAbilityHandler(null);  }}
    

    Internal Ability注册:修改继承AceAbility工程中的代码

    public class MainAbility extends AceAbility {   @Override  public void onStart(Intent intent) {    // 注册, 如果需要在Page初始化(onInit或之前)时调用AceInternalAbility的能力,注册操作需要在super.onStart之前进行    ComputeInternalAbility.register(this);    ...    super.onStart(intent);  }  @Override   public void onStop() {    // 注销    ComputeInternalAbility.unregister();         super.onStop();  }}
    

相关实例

针对JS FA如何调用PA,有以下示例工程可供参考:

  • JsCallJava

    本示例以JS端调用Java端实时获取电池电量为例,帮助开发者了解JS FA调用Java PA的机制。

results matching ""

    No results matching ""