ArkUI eTS 云函数计算十二生肖[Serverless]

Posted 开源基础软件社区官方

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了ArkUI eTS 云函数计算十二生肖[Serverless]相关的知识,希望对你有一定的参考价值。

@toc

eTS+PA+Serverless调试视频

展示eTS+PA+Serverless调试过程视频

1. 前言

通过前面两篇帖子ArkUI eTS 计算十二生肖ArkUI eTS PA计算十二生肖[Service Ability]都是简单同步计算出结果返回,今天我们来个异步计算结果返回,这里用到了Serverless云函数来计算十二生肖,值得注意的是,云函数是异步的,不能马上返回结果,所以通过了订阅事件来获取计算出结果,有时候简单的事情复杂化,可以让我们学到更多的知识,让eTS + PA + Serverless 动起来吧!!!

2. 开通云函数

2.1. 启用云函数服务

首次使用云函数服务前,需要先启用此服务。如果您已经启用,可跳过本步骤。

  1. 登录AppGallery Connect,点击“我的项目”。
  2. 在项目列表中点击需要开通云函数的项目。
  3. 在左侧导航栏选择“构建 > 云函数”,进入云函数页面,在右上角点击“立即开通”。
  4. 如果您已启用多个数据处理位置,当您需要在不同的数据处理位置管理云函数时,可在云函数页面选择“数据处理位置”下拉选项进行切换。

2.2. 创建云函数

启用云函数服务后,您首先需要在AGC中创建函数,并添加函数执行的代码。

  1. 在“函数”页面,点击“创建函数”。
  2. 在创建界面中,完成函数定义。
    • “函数名称”和“描述”栏输入函数名称与描述。
    • “代码输入类型”选择“在线编辑”或“*.zip文件”,选择“在线编辑”可以直接在“代码文件”区域的handler.js文件中编辑函数的代码,AGC提供了默认的myHandler函数代码供您编辑时参考。
  3. 函数创建完成后,复制以下代码, 点击“保存”。

    
    let myHandler = function(event, context, callback, logger) 
    let zodiac = ["猴", "鸡", "狗", "猪", "鼠", "牛", "虎", "兔", "龙", "蛇", "马", "羊"];
    event.body = JSON.parse(event.body);
    let idx = parseInt(event.body.year)%12;
    let sx = zodiac[idx];
    
    let res = new context.HTTPResponse(sx, 
        "res-type": "simple example", 
        "faas-content-type": "json"
    , "application/json", "200");
    
    //send info log
    logger.info("this is message of debug log");
    
    //send info log
    logger.info("this is message of error log");
    
    //send error log
    logger.error("Test error log");
    
    //send response
    callback(res);
    ;

module.exports.myHandler = myHandler;

#### 2.3. 创建触发器
函数创建完成后,需要为函数添加触发器,才可调用到云函数。
1. 在函数列表页面点击已创建的函数名称,进入函数概览页面。
2. 选择“触发器”页签,点击“添加触发器”进行触发器的添加与配置。
3. 添加触发器完成后,可点击创建的触发器查看具体参数。有关触发器的更详细内容,请参见[触发器](https://developer.huawei.com/consumer/cn/doc/development/AppGallery-connect-Guides/agc-cloudfunction-trigger-0000001059279546)。
![image.png](https://dl-harmonyos.51cto.com/images/202207/62daa1962d480af885261295735993d85205a6.png?x-oss-process=image/resize,w_820,h_441)

#### 2.4. 测试函数
函数创建后,您可以在AGC中测试函数的代码运行是否正常。
1. 在函数列表页面点击已创建的函数名称,进入函数概览页面。
2. 选择“代码”页签,使用默认测试事件,或者点击“配置测试参数”配置事件和事件参数,配置完成后点击“测试函数”进行测试。
3. 完成测试后,可在函数测试页面查看测试结果。
有关函数测试的更详细步骤,请参见[测试函数](https://developer.huawei.com/consumer/cn/doc/development/AppGallery-connect-Guides/agc-cloudfunction-test-0000001058801756)。
### 3. 调用云函数
函数创建并测试成功,且创建好触发器后,您即可在您的应用程序中通过调用触发器来调起函数, 调用触发器有两种方法。
- 应用客户端调用:在应用的客户端程序中使用云函数SDK的API调用。
- 应用服务端调用:在应用的服务端程序中使用云函数SDK的API调用。
#### 3.1. 查询触发器标识
当您在创建的函数或函数别名中创建了一个HTTP类型的触发器后,在应用客户端调用函数时需要传入HTTP触发器的标识,查询方法如下:
在函数的触发器页面点击“HTTPTrigger”触发器,查看“触发URL”的后缀,获取触发器的标识,格式为“函数名-版本号”。如下图所示,“myhandlerxxxx-$latest”即为HTTP触发器标识。
![image.png](https://dl-harmonyos.51cto.com/images/202207/b3a548c170bc7ebd3529085af15e13f1eb3528.png?x-oss-process=image/resize,w_820,h_1257)
#### 3.2. 集成云函数SDK
如果需要在应用客户端中调用云函数,则必须集成云函数的客户端SDK。
1. 参考[HarmonyOS使用入门](https://developer.huawei.com/consumer/cn/doc/development/AppGallery-connect-Guides/agc-get-started-harmonyos-0000001184684961)创建应用并集成AGC SDK。
2. 集成云函数SDK。
- HUAWEI DevEco Studio开发环境
添加AGConnect Function依赖到应用级gradle文件中(通常在entry/build.gradle)。
```json
implementation com.huawei.agconnect:agconnect-function-harmony:1.3.1.300

3.3. 调用函数

应用集成了云函数SDK后,可以在应用内直接通过SDK API调用AGC中的云函数,云函数SDK与AGC的函数调用基于HTTPS的安全访问。

  1. 在调用函数前,需要调用AGConnectFunction.getInstance初始化AGConnectFunction实例。
    private AGConnectFunction function;
    function = AGConnectFunction.getInstance();
  2. 调用AGConnectFunction.wrap设置函数,在方法中传入触发器标识。
  3. 根据函数入参情况,调用相关方法来调用函数。
    • 如果函数没有入参,可以调用FunctionCallable.call()来调用函数。
      function.wrap("myhandlerxxxx-$latest").call();
    • 如果函数有入参,可以调用FunctionCallable.call(T object)来调用函数,多个入参添加到object对象中。
      function.wrap("myhandlerxxxx-$latest").call(map);
  4. 如果您需要关注函数的返回值,可以在接口返回的Task中设置一个addOnCompleteListener回调监听,在回调方法中获取包含函数执行结果的FunctionResult对象,调用FunctionResult.getValue可以获取函数执行后的返回值或返回对象。

    private void getWeek(String date) 
     HashMap<String, String> map = new HashMap();
     map.put("time", date);
     function.wrap("myhandlerxxxx-$latest").call(map)
             .addOnCompleteListener(new OnHarmonyCompleteListener<FunctionResult>() 
                 @Override
                 public void onComplete(HarmonyTask<FunctionResult> task) 
                     if (task.isSuccessful()) 
                         String value = task.getResult().getValue();
    
                      else 
                         Exception e = task.getException();
                         if (e instanceof AGCFunctionException) 
                             AGCFunctionException functionException = (AGCFunctionException) e;
                             int errCode = functionException.getCode();
                             String message = functionException.getMessage();
                         
                         // ...
                     
                 
             );
     

    4. Service Ability集成云函数代码片段。

    /**
    * Serverless计算十二生肖
    */
    private void getBornFromServerless() 
    HiLog.info(LABEL_LOG, "xx Java参数:" + year);
    HashMap<String, String> map = new HashMap();
    map.put("year", year + "");
    
    function.wrap("test-zodiac-$latest").call(map)
            .addOnCompleteListener(new OnHarmonyCompleteListener<FunctionResult>() 
                @Override
                public void onComplete(HarmonyTask<FunctionResult> task) 
                    if (task.isSuccessful()) 
                        String value = task.getResult().getValue();
                        HiLog.info(LABEL_LOG, "xxx Java云函数返回生肖: " + value);
                        born = value;
    
                        MessageParcel data = MessageParcel.obtain();
                        MessageParcel reply = MessageParcel.obtain();
                        MessageOption option = new MessageOption();
                        Map<String, Object> result = new HashMap<>();
                        result.put("code", SUCCESS);
                        result.put("abilityResult", born);
                        data.writeString(ZSONObject.toZSONString(result));
                        try 
                            remoteObjectHandler.sendRequest(100, data, reply, option);
                         catch (RemoteException e) 
                            HiLog.error(LABEL_LOG, "xx Java发送事件失败: " + e.getMessage());
                            e.printStackTrace();
                        
                     else 
                        Exception e = task.getException();
                        if (e instanceof AGCFunctionException) 
                            AGCFunctionException functionException = (AGCFunctionException) e;
                            int errCode = functionException.getCode();
                            String message = functionException.getMessage();
                            HiLog.info(LABEL_LOG, "xxx Java ErrCode: " + errCode + ", Message:  " + message);
                        
                    
                
            );
    

    5. Service Ability 订阅与取消订阅代码片段。

    @Override
    public boolean onRemoteRequest(int code, MessageParcel data, MessageParcel reply, MessageOption option) throws RemoteException 
    // code是eTS传参messageCode
    switch (code) 
        case PLUS: 
            HiLog.info(LABEL_LOG, "xx Java计算生肖");
            // 读取参数数据
            String dataStr = data.readString();
            HiLog.info(LABEL_LOG, "xx Java读取参数" + dataStr);
            Map<String, Object> param = new HashMap<>();
            try 
                // 把读取到字符串参数转为Map对象
                param = ZSONObject.stringToClass(dataStr, Map.class);
                // 从对象中获取参数年份
                year = Integer.parseInt( String.valueOf(param.get("year")));
                HiLog.info(LABEL_LOG, "xx Java获取到年份是: " + year);
            catch (RuntimeException e) 
                HiLog.error(LABEL_LOG, "xx Java转换数据失败.");
            
    
            // Serverless计算十二生肖,异步请求,这里先返回调用成功,然后通过订阅事件获取异步结果
            born = "?";
    
            // 返回结果当前仅支持String,对于复杂结构可以序列化为ZSON字符串上报
            Map<String, Object> result = new HashMap<>();
            result.put("code", SUCCESS);
            result.put("abilityResult", born);
            reply.writeString(ZSONObject.toZSONString(result));
    
            break;
        
    // 订阅事件
        case SUBSCRIBE: 
            remoteObjectHandler = data.readRemoteObject();
            getBornFromServerless();
            Map<String, Object> result = new HashMap<String, Object>();
            result.put("code", SUCCESS);
            reply.writeString(ZSONObject.toZSONString(result));
            break;
        
    // 取消订阅
        case UNSUBSCRIBE: 
            remoteObjectHandler = null;
            Map<String, Object> result = new HashMap<String, Object>();
            result.put("code", SUCCESS);
            reply.writeString(ZSONObject.toZSONString(result));
            break;
        
        default: 
            Map<String, Object> result = new HashMap<>();
            result.put("code", ERROR);
            result.put("abilityError", "服务器繁忙, 请稍后再试!!!");
            reply.writeString(ZSONObject.toZSONString(result));
            return false;
        
    
    
    return true;
    

    6. eTS端调用PA传参,并订阅事件,退出时取消订阅

  5. 传年份参数到Service Ability,并成功后订阅事件.

    // Serverless云函数端计算生肖
    getBorn() 
    let that = this;
    
    FeatureAbility.callAbility(
        bundleName: "com.xxx.serverless",
        abilityName: "com.xxx.serverless.ZodiacServiceAbility",
        // abilityType: 0-Ability; 1-Internal Ability
        abilityType: 0,
        messageCode: 1001,
        data: year: this.year,
        // syncOption(Optional, default sync): 0-Sync; 1-Async
        syncOption: 0
    ).then((data) => 
        console.info("xx eTS返回结果是: " + data);
        let jsonObj = JSON.parse(data);
        if(jsonObj.code === 0) 
        // 订阅事件
            that.subscribe();
            that.born = jsonObj.abilityResult;
        else
            AlertDialog.show(
                message: jsonObj.abilityError
            )
        
    )
    
  6. 订阅事件代码片段。
    /**
    * 订阅
    */
    async subscribe() 
    console.info("xx eTS订阅事件")
    let that = this;
    // 调用PA返回十二生肖
    var result = await FeatureAbility.subscribeAbilityEvent(
        bundleName: "com.xxx.serverless",
        abilityName: "com.xxx.serverless.ZodiacServiceAbility",
        abilityType: 0,
        messageCode: 1005,
        syncOption: 0
    , function(callbackData)
            var callbackJson = JSON.parse(callbackData);
            var obj = callbackJson.data;
            if(obj.code === 0) 
                console.info("xx eTS异步返回生肖是:" + obj.abilityResult);
                that.born = obj.abilityResult;
            else
                AlertDialog.show(
                    message: obj.abilityError
                )
            
            console.info(xx eTS事件数据 is:  + JSON.stringify(callbackJson.data));
    );
    var ret = JSON.parse(result);
    if (ret.code == 0) 
        console.info(xx eTS订阅成功, result: + result);
     else 
        console.error(xx eTS订阅失败, result: + result);
    
    
  7. 取消订阅代码片段。
    /**
    * 取消订阅
    */
    async unsubscribe() 
    console.info("xx eTS取消订阅")
    // 调用PA返回十二生肖
    var result = await FeatureAbility.unsubscribeAbilityEvent(
        bundleName: "com.xxx.serverless",
        abilityName: "com.xxx.serverless.ZodiacServiceAbility",
        abilityType: 0,
        messageCode: 1006,
        syncOption: 0
    );
    var ret = JSON.parse(result);
    if (ret.code == 0) 
        console.info(xx eTS取消订阅成功, result: + result);
     else 
        console.error(xx eTS取消订阅失败, result: + result);
    
    
  8. 退出取消订阅
    aboutToDisappear() 
    // 调用取消订阅
    this.unsubscribe();
    

7. 总结

由于PA调用云函数是异步的,传参数给云函数后,不能马上返回结果,然后再返回给eTS端,这里用到了订阅事件,也就是说,像上次在Service Ability计算生肖,eTS调用完后,就会返回结果,但改为在Service Ability里调用云函数,不能马上返回结果,通过订阅事件方式来获取异步返回的结果。 项目源码在gitee上已申请开源,还在审核中,审核通过回复开源地址。

想了解更多关于开源的内容,请访问:

51CTO 开源基础软件社区

https://ost.51cto.com/#bkwz

以上是关于ArkUI eTS 云函数计算十二生肖[Serverless]的主要内容,如果未能解决你的问题,请参考以下文章

OpenHarmony - ArkUI(ETS) 自定义图片查看组件

基于鸿蒙ArkUI的eTS范式开发的仿微信界面程序

HarmonyOS- 基于ArkUI(eTs)实现猫头鹰动画

#物联网征文# OpenHarmony -ArkUI(ETS)之WiFi简单的连接操作

#DAYU200体验官# ArkUI eTS实践开发一个管家服务系统

#打卡不停更# HarmonyOS 基于ArkUI(ETS) 实现雷达扫描