HarmonyOS学习路之开发篇—Java UI框架(JS FA调用Java PA)

简介: 使用兼容JS的类Web开发范式的方舟开发框架提供了JS FA(Feature Ability)调用Java PA(Particle Ability)的机制,该机制提供了一种通道来传递方法调用、处理数据返回以及订阅事件上。

JS FA调用Java PA机制

使用兼容JS的类Web开发范式的方舟开发框架提供了JS FA(Feature Ability)调用Java PA(Particle Ability)的机制,该机制提供了一种通道来传递方法调用、处理数据返回以及订阅事件上。


当前提供Ability和Internal Ability两种调用方式。


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

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

对于Internal Ability调用方式的开发,可以使用工具自动生成代码(自动生成下篇文章详解),提高开发效率。


JS端与Java端通过bundleName和abilityName来进行关联。在系统收到JS调用请求后,根据开发者在JS接口中设置的参数来选择对应的处理方式。开发者在onRemoteRequest()中实现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进行处理,因此需要检查以下几点是否正确执行:


在AceAbility继承类中对AceInternalAbility继承类执行了register方法,具体注册可参考Internal Ability的示例代码。

JS侧填写的bundleName和abilityName与AceInternalAbility继承类构造函数中填写的名称保持相同,大小写敏感。

检查JS端填写的abilityType(0:Ability; 1:Internal Ability),确保没有将AbilityType缺省或误填写为Ability方式。

Ability和Internal Ability是两种不同的FA调用PA的方式。


Ability和InternalAbility差异项



image.png


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端接收后返回两个数的和。


JS FA应用的JS模块(entry/src/main)的典型开发目录结构如下:



5764a7869a9da19086792f46e4a4a284.png

FA JavaScript端

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


// 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.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();
  }
}
相关文章
|
1月前
|
移动开发 JavaScript 应用服务中间件
【06】优化完善落地页样式内容-精度优化-vue加vite开发实战-做一个非常漂亮的APP下载落地页-支持PC和H5自适应提供安卓苹果鸿蒙下载和网页端访问-优雅草卓伊凡
【06】优化完善落地页样式内容-精度优化-vue加vite开发实战-做一个非常漂亮的APP下载落地页-支持PC和H5自适应提供安卓苹果鸿蒙下载和网页端访问-优雅草卓伊凡
212 5
【06】优化完善落地页样式内容-精度优化-vue加vite开发实战-做一个非常漂亮的APP下载落地页-支持PC和H5自适应提供安卓苹果鸿蒙下载和网页端访问-优雅草卓伊凡
|
1月前
|
移动开发 Android开发
【03】建立隐私关于等相关页面和内容-vue+vite开发实战-做一个非常漂亮的APP下载落地页-支持PC和H5自适应提供安卓苹果鸿蒙下载和网页端访问-优雅草卓伊凡
【03】建立隐私关于等相关页面和内容-vue+vite开发实战-做一个非常漂亮的APP下载落地页-支持PC和H5自适应提供安卓苹果鸿蒙下载和网页端访问-优雅草卓伊凡
128 0
|
1月前
|
移动开发 前端开发 Android开发
【02】建立各项目录和页面标准化产品-vue+vite开发实战-做一个非常漂亮的APP下载落地页-支持PC和H5自适应提供安卓苹果鸿蒙下载和网页端访问-优雅草卓伊凡
【02】建立各项目录和页面标准化产品-vue+vite开发实战-做一个非常漂亮的APP下载落地页-支持PC和H5自适应提供安卓苹果鸿蒙下载和网页端访问-优雅草卓伊凡
246 12
【02】建立各项目录和页面标准化产品-vue+vite开发实战-做一个非常漂亮的APP下载落地页-支持PC和H5自适应提供安卓苹果鸿蒙下载和网页端访问-优雅草卓伊凡
|
1月前
|
移动开发 Rust JavaScript
【01】首页建立-vue+vite开发实战-做一个非常漂亮的APP下载落地页-支持PC和H5自适应提供安卓苹果鸿蒙下载和网页端访问-优雅草卓伊凡
【01】首页建立-vue+vite开发实战-做一个非常漂亮的APP下载落地页-支持PC和H5自适应提供安卓苹果鸿蒙下载和网页端访问-优雅草卓伊凡
543 4
【01】首页建立-vue+vite开发实战-做一个非常漂亮的APP下载落地页-支持PC和H5自适应提供安卓苹果鸿蒙下载和网页端访问-优雅草卓伊凡
|
2月前
|
传感器 监控 安全
HarmonyOS NEXT 5.0 的星闪(NearLink)开发应用案例
V哥分享HarmonyOS NEXT 5.0星闪开发实战,涵盖智能车钥匙无感解锁与工业传感器监控。低延迟、高可靠,代码完整,速来学习!
495 0
|
2月前
|
存储 缓存 5G
鸿蒙 HarmonyOS NEXT端云一体化开发-云存储篇
本文介绍用户登录后获取昵称、头像的方法,包括通过云端API和AppStorage两种方式,并实现上传头像至云存储及更新用户信息。同时解决图片缓存问题,添加上传进度提示,支持自动登录判断,提升用户体验。
164 1
|
2月前
|
存储 负载均衡 数据库
鸿蒙 HarmonyOS NEXT端云一体化开发-云函数篇
本文介绍基于华为AGC的端云一体化开发流程,涵盖项目创建、云函数开通、应用配置及DevEco集成。重点讲解云函数的编写、部署、调用与传参,并涉及环境变量设置、负载均衡、重试机制与熔断策略等高阶特性,助力开发者高效构建稳定云端服务。
365 1
鸿蒙 HarmonyOS NEXT端云一体化开发-云函数篇
|
2月前
|
存储 JSON 数据建模
鸿蒙 HarmonyOS NEXT端云一体化开发-云数据库篇
云数据库采用存储区、对象类型、对象三级结构,支持灵活的数据建模与权限管理,可通过AGC平台或本地项目初始化,实现数据的增删改查及端侧高效调用。
164 1
|
2月前
|
存储 开发者 容器
鸿蒙 HarmonyOS NEXT星河版APP应用开发-ArkTS面向对象及组件化UI开发使用实例
本文介绍了ArkTS语言中的Class类、泛型、接口、模块化、自定义组件及状态管理等核心概念,并结合代码示例讲解了对象属性、构造方法、继承、静态成员、访问修饰符等内容,同时涵盖了路由管理、生命周期和Stage模型等应用开发关键知识点。
301 1
鸿蒙 HarmonyOS NEXT星河版APP应用开发-ArkTS面向对象及组件化UI开发使用实例
|
2月前
鸿蒙 HarmonyOS NEXT星河版APP应用开发-阶段三
本文介绍了UI开发中的样式复用与组件构建技术,涵盖@Extend、@Styles和@Builder的使用方法,并通过Swiper轮播、Scroll滚动、Tabs导航等常用组件实现典型界面效果,结合生肖抽卡、小米轮播、回顶按钮等案例,展示实际应用技巧。
124 1

热门文章

最新文章