HarmonyOS开发5.0【rcp的封装与应用】

何为rcp?

rcp 即 Remote Communication Protocol(远场通信协议)。在HarmonyOS中,它的实现集成在Remote Communication Kit(远场通信服务)中,是华为提供的HTTP发起数据请求的NAPI封装。

应用通过Remote Communication Kit可以便捷快速地向服务器发起数据请求,rcp支持HTTP的GET、POST、OPTIONS等请求,提供了丰富的业务场景。

我们知道,在鸿蒙SDK的系统服务中,网络请求相关服务已经有了NetWork Kit了,为什么还需要使用rcp呢?可以知道:

http原生库能力还在维护中,ohos.net.http暂不会再演进或新增其他功能,当前推荐使用hms.collaboration.rcp能力替代,在接口易用性、性能、功耗方面比http网络库好。

因此官方推荐使用rcp,我们也需要紧跟官方的步伐,赶快用起来~

使用Remote Communication Kit的主要业务流程如下:

  1. 应用客户端创建会话。
  2. 应用客户端发起请求。
  3. 应用客户端接收请求结果,处理相应业务。

如何使用

首先,需要申请网络权限,在entry/src/main路径下的module.json5中配置如下:

{
  "module": {
    "requestPermissions": [
      {
        "name": "ohos.permission.INTERNET"
      },
      {
        "name": "ohos.permission.GET_NETWORK_INFO"
      }
    ]
  }
}

然后,在需要使用该能力的.ets文件中导入rcp:

import { rcp } from "@kit.RemoteCommunicationKit";

这样,我们就可以使用rcp的能力了。

封装

rcp的使用场景很多,一般场景有:

  • 获取服务器资源
  • 发送数据到服务器
  • 断点续传
  • 双向证书校验
  • 拦截器 …

我们可以对一些主要场景进行封装,达到在项目中方便易用的效果。

这里,我们创建一个工具类HTTPRequestUtil,并声明一个rcp.Configuration和一个rcp.RequestHeaders供全局调用:

const configuration: rcp.Configuration = {
  transfer: {
    autoRedirect: true,
    timeout: {
      // 允许建立连接的最长时间
      connectMs: HTTP_TIMEOUT,
      // 允许传输数据的最长时间
      transferMs: HTTP_TIMEOUT,
    }
  }
};

const header: rcp.RequestHeaders = {
  'content-type': 'application/json'
}

接着,再创建一个session

// Use the configuration in the session creation
  private static session = rcp.createSession({ requestConfiguration: configuration });

这个session是创建rcp网络请求或连接的基础,由此发起相关事务。 我们可以使用sessionfetch能力发起一个HTTP请求,并获取返回结果:

private static sendRequest(url: string, method: rcp.HttpMethod, params: Record<string, string>, succeedCallback: Callback<rcp.Response>, failedCallback: Callback<BusinessError>) {
    let req = new rcp.Request(url);
    if (params) req.content = JSON.stringify(params);
    req.method = method.toUpperCase();
    req.headers = header;

    HTTPRequestUtil.session.fetch(req).then((response) => {
      LogUtil.info("RCP request succeed: " + JSON.stringify(response));
      succeedCallback(response);
      HTTPRequestUtil.session.close();
    }).catch((err: BusinessError) => {
      LogUtil.error("RCP request failed: " + err);
      HTTPRequestUtil.session.close();
      failedCallback(err);
    });
  }

可以看出,以上方法基于参数回调,返回结果和错误都会通过回调返回。 我们也可以通过Promise的方式异步返回结果:

private static async sendRequestP(url: string, method: rcp.HttpMethod, params: Record<string, string>): Promise<rcp.Response | BusinessError> {
    let req = new rcp.Request(url);
    if (params) req.content = JSON.stringify(params);
    req.method = method.toUpperCase();
    req.headers = header;
    req.configuration = configuration;

    try {
      let res = await HTTPRequestUtil.session.fetch(req);
      LogUtil.info("RCP request succeed: " + JSON.stringify(res));
      return res;
    } catch (err) {
      LogUtil.error("RCP request failed: " + err);
      return err as BusinessError;
    } finally {
      HTTPRequestUtil.session.close();
    }
  }

这样,我们就可以通过传入参数的method变化实现一般的GET、POST、PUT等HTTP请求。

通过回调返回的可以实现如下:

  /**
   * 发送 GET 请求
   * @param url: URL
   * @param params: 参数
   * @param succeedCallback: 成功回调
   * @param failedCallback: 失败回调
   *
   * @returns 通过回调返回
   */
static GET(url: string, params: Record<string, string>, succeedCallback: Callback<rcp.Response>, failedCallback: Callback<BusinessError>) {
    HTTPRequestUtil.sendRequest(url, "GET", params, (response: rcp.Response) => {
      succeedCallback(response);
    }, (err: BusinessError) => {
      failedCallback(err);
    });
  }


  /**
   * 发送 POST 请求
   * @param url: URL
   * @param params: 参数
   * @param succeedCallback: 成功回调
   * @param failedCallback: 失败回调
   *
   * @returns 通过回调返回
   */
  static POST(url: string, params: Record<string, string>, succeedCallback: Callback<rcp.Response>, failedCallback: Callback<BusinessError>) {
    HTTPRequestUtil.sendRequest(url, "POST", params, (response: rcp.Response) => {
      succeedCallback(response);
    }, (err: BusinessError) => {
      failedCallback(err);
    });
  }

  /**
   * 发送 PUT 请求
   * @param url: URL
   * @param params: 参数
   * @param succeedCallback: 成功回调
   * @param failedCallback: 失败回调
   *
   * @returns 通过回调返回
   */
  static PUT(url: string, params: Record<string, string>, succeedCallback: Callback<rcp.Response>, failedCallback: Callback<BusinessError>) {
    HTTPRequestUtil.sendRequest(url, "PUT", params, (response: rcp.Response) => {
      succeedCallback(response);
    }, (err: BusinessError) => {
      failedCallback(err);
    });
  }


  /**
   * 发送 DELETE 请求
   * @param url: URL
   * @param params: 参数
   * @param succeedCallback: 成功回调
   * @param failedCallback: 失败回调
   *
   * @returns 通过回调返回
   */
  static DELETE(url: string, params: Record<string, string>, succeedCallback: Callback<rcp.Response>, failedCallback: Callback<BusinessError>) {
    HTTPRequestUtil.sendRequest(url, "DELETE", params, (response: rcp.Response) => {
      succeedCallback(response);
    }, (err: BusinessError) => {
      failedCallback(err);
    });
  }

其使用十分简便:

HTTPRequestUtil.GET(url, {}, (res) => {
  // 返回结果
}, (err) => {
  // 错误处理
});

如果你希望通过Promise返回,同样可以实现如下:

/**
   * 发送 GET 请求(通过 Promise 返回)
   * @param url: URL
   * @param params: 参数
   *
   * @returns Promise 返回结果
   */
  static async get(url: string, params: Record<string, string>): Promise<rcp.Response | BusinessError> {
    try {
      const response = await HTTPRequestUtil.sendRequestP(url, "GET", params);
      return response;
    } catch (error) {
      return error;
    }
  }

  /**
   * 发送 POST 请求(通过 Promise 返回)
   * @param url: URL
   * @param params: 参数
   *
   * @returns Promise 返回结果
   */
  static async post(url: string, params: Record<string, string>): Promise<rcp.Response | BusinessError> {
    try {
      const response = await HTTPRequestUtil.sendRequestP(url, "POST", params);
      return response;
    } catch (error) {
      return error;
    }
  }

  /**
   * 发送 PUT 请求(通过 Promise 返回)
   * @param url: URL
   * @param params: 参数
   *
   * @returns Promise 返回结果
   */
  static async put(url: string, params: Record<string, string>): Promise<rcp.Response | BusinessError> {
    try {
      const response = await HTTPRequestUtil.sendRequestP(url, "PUT", params);
      return response;
    } catch (error) {
      return error;
    }
  }

  /**
   * 发送 DELETE 请求(通过 Promise 返回)
   * @param url: URL
   * @param params: 参数
   *
   * @returns Promise 返回结果
   */
  static async delete(url: string, params: Record<string, string>): Promise<rcp.Response | BusinessError> {
    try {
      const response = await HTTPRequestUtil.sendRequestP(url, "DELETE", params);
      return response;
    } catch (error) {
      return error;
    }
  }

同样,我们可以通过一行代码进行调用:

let res = await HTTPRequestUtil.get(url, "");
LogUtil.info(`HTTPRequestUtil succeed: ${res}`);

我们还可以实现下载文件流程:

/**
   * 下载文件
   * @param url: URL
   * @param toPath: 文件保存路径
   *
   * @returns 通过回调返回
   */
   async downloadFile(url: string, filename: string, progressCallback: (progress: number) => void, succeedCallback: (filepath: string) => void, failedCallback:(err: BusinessError) => void) {
     // Define a custom response handler
     const customHttpEventsHandler: rcp.HttpEventsHandler = {
       onDownloadProgress: (totalSize: number, transferredSize: number) => {
         // Custom logic for handling download progress
         console.info("Download progress:", transferredSize, "of", totalSize);
         let proc = Math.ceil(transferredSize / totalSize * 100);
         progressCallback(proc);
       }
     };

     // Configure tracing settings
     const tracingConfig: rcp.TracingConfiguration = {
       verbose: true,
       infoToCollect: {
         textual: true,
         incomingHeader: true,
         outgoingHeader: true,
         incomingData: true,
         outgoingData: true,
         incomingSslData: true,
         outgoingSslData: true,
       },
       collectTimeInfo: true,
       httpEventsHandler: customHttpEventsHandler,
     };

     // Use the configuration in the session creation
     const session = rcp.createSession({ requestConfiguration: { tracing: tracingConfig } });

     try {
      // 获取保存全路径
      let finalPath = FileUtil.getFilesDirPath('', filename);
      let fileDir = FileUtil.getFilesDirPath('');
      let fn = FileUtil.getFileName(finalPath);
      let path = finalPath.replace(fn, "");
      let isExists = fs.accessSync(finalPath);

      if (isExists) {
        fs.unlinkSync(finalPath);
      } else {
        if (path != fileDir + '/') {
          FileUtil.mkdirSync(path, true);
        }
      }

      let downloadToFile: rcp.DownloadToFile = {
        kind: "file",
        file: finalPath
      } as  rcp.DownloadToFile

      await session.downloadToFile(url, downloadToFile);

      LogUtil.info("File path: " + finalPath);
      succeedCallback(finalPath);
    } catch (err) {
      LogUtil.error("HTTPRequestUtil download file error:" + err);
      failedCallback(err);
    }
  }

}

这里有个关键点在于获取下载进度,这一监听在rcp.HttpEventsHandleronDownloadProgress中,我们可以在这里实时返回当前进度,如果需要返回一个百分比的数值,可以使用Math.ceil进行转换:let proc = Math.ceil(transferredSize / totalSize * 100);

如需取消下载,可调用session.cancel()

总结

这里,我们对rcp的部分功能进行了封装尝试,当然,这只是其中很少的一部分。rcp的能力正如我在前文中列举的那样很强大很全面,如果你需要在项目中用到其他能力,可以尝试按照官方文档进行封装与优化。

最后呢

很多开发朋友不知道需要学习那些鸿蒙技术?鸿蒙开发岗位需要掌握那些核心技术点?为此鸿蒙的开发学习必须要系统性的进行。

而网上有关鸿蒙的开发资料非常的少,假如你想学好鸿蒙的应用开发与系统底层开发。你可以参考这份资料,少走很多弯路,节省没必要的麻烦。由两位前阿里高级研发工程师联合打造的《鸿蒙NEXT星河版OpenHarmony开发文档》里面内容包含了(ArkTS、ArkUI开发组件、Stage模型、多端部署、分布式应用开发、音频、视频、WebGL、OpenHarmony多媒体技术、Napi组件、OpenHarmony内核、Harmony南向开发、鸿蒙项目实战等等)鸿蒙(Harmony NEXT)技术知识点

如果你是一名Android、Java、前端等等开发人员,想要转入鸿蒙方向发展。可以直接领取这份资料辅助你的学习。下面是鸿蒙开发的学习路线图。
在这里插入图片描述

针对鸿蒙成长路线打造的鸿蒙学习文档。话不多说,我们直接看详细鸿蒙(OpenHarmony )手册(共计1236页)与鸿蒙(OpenHarmony )开发入门视频,帮助大家在技术的道路上更进一步。

  • 《鸿蒙 (OpenHarmony)开发学习视频》
  • 《鸿蒙生态应用开发V2.0白皮书》
  • 《鸿蒙 (OpenHarmony)开发基础到实战手册》
  • OpenHarmony北向、南向开发环境搭建
  • 《鸿蒙开发基础》
  • 《鸿蒙开发进阶》
  • 《鸿蒙开发实战》

在这里插入图片描述

2

mau123789
  • 7
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值