更新时间:2025-08-19 GMT+08:00
分享

快速开始

  1. 在工程libs下导入aar。

    将cloudphone-merge-cloudapp-xxx-kp.hmtp-cabin-xxx.aar放到工程libs下引入。

  2. 初始化SDK。

    1. 在AppAplication中初始化串流SDK。
      CloudPhoneClient.init(Application application, Callback callback, boolean openLog);
      CloudPhoneClient.playerForceTextureView(false);
      CloudPhoneClient.setLogFolder(this.getExternalFilesDir("log").getPath() + File.separator);

      初始化说明:

      • callback:非必填,云机串流的结果及中途异常消息回调,初始化可空。
      • openLog:是否输出log,是否加密本地日志文件。

      传入日志文件位置:由于安全合规且自定义,需要传入app私有路径,方便排查。

    1. 获取IAM token,可参考文档获取IAM用户Token

      接口地址:POST https://iam.myhuaweicloud.com/v3/auth/tokens?nocatalog=true。

      请求示例:

      {
          "auth": {
              "identity": {
                  "methods": [
                      "password"
                  ],
                  "password": {
                      "user": {
                          "domain": {
                              "name": "IAMDomain"        //IAM用户所属账号名
                          },
                          "name": "IAMUser",             //IAM用户名
                          "password": "IAMPassword"      //IAM用户密码
                      }
                  }
              },
              "scope": {
                  "project": {
                      "name": "cn-north-1"               //项目名称
                  }
              }
          }
      }

      获取token:

      响应Header参数(获取到的Token):
      X-Subject-Token:MIIatAYJKoZIhvcNAQcCoIIapTCCGqECAQExDTALB...

  3. 串流打开数据通道。

    1. 获取云机设备token与地址信息,可参考文档租户实例串流前获取设备的device_token

      接口地址:POST https://koophone.myhuaweicloud.com/v1/instances/{instance_id}/auth。

      请求示例

      post接口,请求url中携带租户自己购买的实例和租户的token直接调用。

      /v1/instances/xxxxxx/auth

      响应示例

      状态码:200

      实例鉴权接口返回设备信息。

      {
        "data" : {
          "resource" : {
            "sdk" : {
              "internal" : {
                "address" : null,
                "aport" : null,
                "atype" : null,
                "address_ipv6" : null
              },
              "external" : {
                "address" : "10.83.71.187",
                "aport" : 10030,
                "atype" : 1,
                "address_ipv6" : null
              }
            },
            "rtc" : {
              "ice_signaling" : {
                "signaling_url" : "http://100.93.2.248:18082",
                "expired_time" : null,
                "ice_servers" : [ ]
              }
            },
            "device_id" : "7b0cd026df8d495b8a65d628d7bec433",
            "kp_id" : "Q39YyZvI"
          },
          "device_token" : "dee5081f40c83ddea3ded91c387351e9"
        },
        "error_code" : "0",
        "error_msg" : "ok"
      }
    1. 启动串流。
      关于CloudPhoneClient其他公开方法说明可参考表1
      表1 CloudPhoneClient方法名及参数说明

      方法名及参数

      说明

      start(PlayerFragment mPlayerFragment, Bundle extras)

      开始串流

      closeApp(String packageName)

      通过应用包名强制关闭云手机中运行的目标应用

      startApp(String packageName)

      通过包名/类名或Scheme协议启动目标应用,支持传递自定义参数

      uninstallApp(String packageName)

      通过应用包名卸载云手机中的指定应用(系统级静默卸载,无需用户确认)

      getRunningApps(GetAppsReq req)

      查询当前云手机环境中正在运行的应用列表及其状态信息

      switchStreamType(String type)

      改变串流类型

      streamType枚举:

      • DATA:仅数据传输通道
      • VIDEO:仅拉取视频流,不拉取音频流,包含DATA
      • AUDIO:仅拉取音频流,不拉取视频流,包含DATA
      • BOTH:启动后音视频正常拉流,默认,包含DATA

      void setPlayerCallback(Callback callback)

      串流回调注册

      void setUnPlayerCallback(Callback callback)

      串流回调注销,断开串流需要移除

      void stop()

      主动断开串流调用该方法

      String version()

      获取当前版本号

      boolean setProfile(int level)

      设置清晰度档位。0:自动,1:流畅,2:高清,3:超清

      void mute(boolean mute)

      设置静音

      boolean isPlaying()

      判断当前是否串流中

      sendExtMessageToCloud(String message)

      发送消息到云端App。message消息体(json格式的字符串)

      setCloudScreenAspect(int screenWidth, int screenHeight)

      动态设置云机画面比例。screenWidth:真机屏幕宽,screenHeight:真机屏幕高

      void enableAudioKeeping(boolean isKeep)

      保持后台保活

      void setSensorEvent(boolean isLandscape);

      设置串流横屏或者竖屏显示。true:横屏,false:竖屏

      sendKeyEvent(int keycode)

      KeyEvent.KEYCODE_BACK,KeyEvent.KEYCODE_HOME,KeyEvent.KEYCODE_APP_SWITCH

      1. 在MainActivity中根据接口获取到的token与设备信息组装串流参数打开数据通道串流。
          public void jumpTargetApp(ApiResponse authResponseResponseBean) {
                Bundle bundle = new Bundle();
                if (authResponseResponseBean != null && null != authResponseResponseBean.getData()) {
                    ApiResponse.Data data = authResponseResponseBean.getData();
                    //校验token,后台返回 如果云机校验失败会返回100002异常码
                    bundle.putString(CLOUD_APP_LAUNCH_KEY_TOKEN, TextUtils.isEmpty(data.getDevice_token()) ? "" : data.getDevice_token());
                    ApiResponse.Data.Resource resource = data.getResource();
                    if (null != resource) {
                        ApiResponse.Data.Resource.Sdk sdk = resource.getSdk();
                        if (null != sdk) {
                            ApiResponse.Data.Resource.Sdk.External external = sdk.getExternal();
                            if (null != external) {
                                //address 云机ip,后台返回
                                bundle.putString(CLOUD_APP_LAUNCH_KEY_ADDRESS, external.getAddress());
                                //aport:云机端口,后台返回
                                bundle.putInt(CLOUD_APP_LAUNCH_KEY_PORT, external.getAport());
                                //atype:后台返回
        //                        bundle.putInt(CLOUD_APP_LAUNCH_KEY_TYPE, external.getAtype());
                                bundle.putInt(CLOUD_APP_LAUNCH_KEY_TYPE, 8);
                                bundle.putInt(CLOUD_APP_LAUNCH_KEY_V_TYPE, 8);
                            }
                        }
                    }
                }
                //后台返回,有就填
        //        bundle.putString(CLOUD_APP_LAUNCH_KEY_BUILD_DEVICE,"");
                // 强制开启H264
        //        bundle.putInt(CLOUD_APP_LAUNCH_KEY_VENC_TYPE, 0);
                // 强制开启H265
                bundle.putInt(CLOUD_APP_LAUNCH_KEY_VENC_TYPE, 1);
                bundle.putInt(CLOUD_APP_LAUNCH_KEY_PROFILE_LEVEL, PROFILE_SPEED);
                //多云机共用用户id,可用用户登录id,也可自定义,保证不与其他用户相同
                bundle.putString("userId", "43740902807");
                bundle.putBoolean(CLOUD_APP_HIDE_STREAM_AT_START_UP, true);
        //        if (!TextUtils.isEmpty(pkg)) {
        //            bundle.putString("pkgs", pkg);
        //        }
                //开启
                bundle.putBoolean("free_aspect", true);
                bundle.putInt("screen_width", 1920);//任意分辨率宽
                bundle.putInt("screen_height", 1080);//任意分辨率高
                CloudPhoneClient.setPlayerType(HMTP_PLAYER);
                CloudPhoneCallBack callBack = CloudPhoneCallBack.getInstance();
                callBack.setStartHandler(v->onStreamStarted());
                callBack.setAppHandler(this::updateAppList);
                callBack.setStartAppHandler(v->startApp());
                CloudPhoneClient.enableAudioKeeping(true);
                CloudPhoneClient.setPlayerCallback(callBack);
                CloudPhoneClient.setAppCallback(callBack);
                //执行串流的,串流结果成功会从onSuccsss返回通知,失败则是onFailure带code
                CloudPhoneClient.start(null, bundle);
            }
      2. 串流回调结果Callback。

        需要在串流界面内注册Callback。

        1. 注册用回调CloudPhoneClient.setPlayerCallback(new Callback())。
        2. 注册应用操作回调。
          CloudPhoneClient.setAppCallback(callBack);
        3. 退出云机注销CloudPhoneClient.setUnPlayerCallback(this)。
      3. 接受到串流回调onStreamStarted加载应用墙。

  4. 应用墙MainActivity显示应用列表。

    查询云机中已安装的应用列表,与本地缓存或数据库保存的应用白名单匹配,取并集后把应用列表显示到应用墙上。
    1. 调用SDK接口可以获取云机已经安装的应用列表。
      CloudPhoneClient.getInstalledApps(GetAppsReq req)

      请求参数GetAppsReq的参数说明参考表2

      表2 GetAppsReq参数说明

      参数名

      类型

      描述

      约束条件

      appType

      AppTypeEnum

      应用类型筛选(必填)

      枚举值:SYSTEM_APP(系统应用)、THIRD_APP(第三方应用)、BOTH(全部)

      quality

      Integer

      图标质量参数(选填,默认100)

      取值范围0-100,建议取值为70~85以平衡清晰度与大小

      pageNum

      Integer

      分页页码(必填)

      从1开始,需配合pageSize使用

      pageSize

      Integer

      分页大小(必填)

      最大支持20条/页

      needIcon

      Boolean

      是否返回图标(必填)

      true返回图标数据/URL,false不返回图标相关字段

      getInstalledApps的回调参数说明参考表3

      表3 getInstalledApps回调参数说明

      字段

      类型

      业务说明

      error_code

      String

      状态码(0=成功)

      error_msg

      String

      错误详情

      data

      GetAppsRsp

      磁盘使用数据对象

      回调接口通过CloudPhoneClient.setAppCallback(CloudPhoneClient.Callback.AppCallback callback) 注册,回调参数为AppOperateResponse<GetAppsRsp>,其中GetAppsRsp结构参考表4

      表4 GetAppsRsp整体结构

      参数名

      类型

      描述

      appList

      List

      应用列表(分页数据)

      totalCount

      Integer

      符合筛选条件的应用总数

      pageNum

      Integer

      当前分页页码(与请求参数一致)

      pageSize

      Integer

      当前分页大小(与请求参数一致)

      CloudAppInfo应用详情结构参考表5

      表5 CloudAppInfo整体结构

      参数名

      类型

      描述

      说明

      appName

      String

      应用名称

      如“微信”、“设置”

      packageName

      String

      应用包名(唯一标识)

      如“com.tencent.mm ”

      icon

      String

      WebP格式图标原始数据Base64编码

      仅当needIcon=true时可能返回,null表示无数据

      iconUrl

      String

      WebP格式图标URL

      端侧优先使用此字段,无值时allback到icon字节数组

      isReady

      Boolean

      应用是否准备就绪(可启动状态)

      true表示应用可正常使用,false可能为未安装完成或异常状态

    1. 打开串流应用。
      CloudPhoneClient.startApp(pkgName);
      收到打开应用成功回调onStartApp后打开串流页面。
      private void startApp(){
          //点击事件:
          Intent intent = new Intent(context, HuaweiCloudActivity.class);
          intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);
          startActivity(intent);
      }
      private void initPlayer(Bundle savedInstanceState) {
          mPlayerFragment = (PlayerFragment) getFragmentManager().findFragmentById(R.id.fragment_player);
          callBack = CloudPhoneCallBack.getInstance();
          callBack.setProfileHandler(this::profileReceived);
          CloudPhoneClient.setPlayerCallback(callBack);
          CloudPhoneClient.setPlayerType(HMTP_PLAYER);
          CloudPhoneClient.bindFragment(mPlayerFragment);
          CloudPhoneClient.switchStreamType(CloudPhoneConst.CLOUD_APP_SWITCH_STREAM_TYPE.BOTH);
      }

      Callback回调列表以及onFailure回调异常码。

      public interface Callback {
      /**
      * 串流成功返回,调用start()开始串流方法后 成功就会返回
      */
      void onSuccess();
      
      /**
      * 串流断开,主动或被动 可认为是串流最后一次回调 可以收到回调后处理释放资源
      */
      void onTerminated();
      
      /**
      * 数据通道串流成功回调
      **/
      @Override
      public void onStreamStarted() {
          if(startHandler!=null){
              startHandler.accept(null);
          }
      }
      /**
      * 开始串流start()失败以及串流中失败异常回调
      *
      * @param code    错误码
      * @param message 错误消息
      */
      void onFailure(int code, String message);
      
      /**
      * 云机屏幕方向改变
      *
      * @param orientation 参考Android横竖屏 {@link android.content.pm.ActivityInfo#SCREEN_ORIENTATION_LANDSCAPE} or {@link android.content.pm.ActivityInfo#SCREEN_ORIENTATION_PORTRAIT}
      */
      void onOrientationChange(int orientation);
      
      /**
      * 按固定周期的回调,展示实时串流的信息,包括分辨率,码率,帧率
      *
      * @param profile {"fps":"30","br":"2.24Mb","rtt":"14ms","resolution":"720x1280"}
      */
      void onProfileReceived(String profile);
      
      /**
      * 客户端发起分辨率修改接口setProfile之后,产生的回调,展示修改结果
      *
      * @param level
      * @param isForceDSD 是否被强制降挡 当setProfile的level不支持 需要降低档位level
      */
      void onProfileChanged(int level,boolean isForceDSD);
      
      
      /**
      * 云侧扩展消息通道
      *
      * @param act     上下文,自定义UI时为空
      * @param message 消息体
      */
      void onExtMessageReceived(Activity act, String message);
      
      /**
      * "服务端主动断流回调(典型场景:多端登录时,云侧回调给端侧的踢出串流信息,收到回调时,客户端需要提示有其他端登录)
      * @param message 提示信息
      */
      void onKicked(String message);
      }

      onFailure异常码列表。

      /**
      * 内部错误
      */
      public static final int CLOUD_APP_RET_CODE_INTERNAL_ERROR = 100000;//内部错误
      /**
      * 无效的启动参数
      */
      public static final int CLOUD_APP_RET_CODE_INVALID_PARAMS = 100001;//无效的启动参数
      /**
      * token无效,检查启动参数accessToken或secretKey是否正确
      */
      public static final int CLOUD_APP_RET_CODE_INVALID_TOKEN = 100002;//token无效,检查启动参数accessToken或secretKey是否正确
      /**
      * sdk版本不匹配,更新最新的sdk版本
      */
      public static final int CLOUD_APP_RET_CODE_INVALID_VERSION = 100003;//sdk版本不匹配,更新最新的sdk版本
      /**
      * 应用未找到,检查云机是否安装应用
      */
      public static final int CLOUD_APP_RET_CODE_GAME_NOT_FOUND = 100004;//应用未找到,检查云机是否安装应用
      /**
      * 应用启动失败,检查云机安装应用是否正常运行
      */
      public static final int CLOUD_APP_RET_CODE_GAME_LAUNCH_FAIL = 100005;//应用启动失败,检查云机安装应用是否正常运行
      /**
      * 用户主动退出
      */
      public static final int CLOUD_APP_RET_CODE_USER_EXIT = 100008;//用户主动退出
      /**
      * 用户重复登录
      */
      public static final int CLOUD_APP_RET_CODE_DUPLICATE_USER = 100009;//用户重复登录
      /**
      * 后端主动断开streaming
      */
      public static final int CLOUD_APP_RET_STOP_STREAMING = 100010;//后端主动断开streaming
      
      /**
      * 连接服务器失败
      */
      public static final int CLOUD_APP_RET_CODE_CONNECT_FAIL = 110000;//连接服务器失败
      /**
      * 请求异常,服务器未能正常响应(如404、500...)
      */
      public static final int CLOUD_APP_RET_CODE_CONNECT_ERROR = 110001;//请求异常,服务器未能正常响应(如404、500...)
      /**
      * player与云机断开连接、断线
      */
      public static final int CLOUD_APP_RET_CODE_DROP_LINE = 110003;//player与云机断开连接、断线
      /**
      * 心跳超时
      */
      public static final int CLOUD_APP_RET_CODE_HEARTBEAT_TIMEOUT = 110004;//心跳超时
      /**
      * 云机服务异常
      */
      public static final int CLOUD_APP_RET_CODE_STRM_SERVER_ERROR = 110006;//云机服务异常
      
      /**
      * 云机服务忙
      */
      public static final int CLOUD_APP_RET_CODE_STRM_SERVICE_BUSY = 5021107;//云机服务忙

相关文档