快速开始
- 在工程libs下导入aar。
将cloudphone-merge-cloudapp-xxx-kp.hmtp-cabin-xxx.aar放到工程libs下引入。
- 初始化SDK。
- 在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私有路径,方便排查。
- 获取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...
- 在AppAplication中初始化串流SDK。
- 串流打开数据通道。
- 获取云机设备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" }
- 启动串流。
关于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
- 在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); }
- 串流回调结果Callback。
- 注册用回调CloudPhoneClient.setPlayerCallback(new Callback())。
- 注册应用操作回调。
CloudPhoneClient.setAppCallback(callBack);
- 退出云机注销CloudPhoneClient.setUnPlayerCallback(this)。
- 接受到串流回调onStreamStarted加载应用墙。
- 获取云机设备token与地址信息,可参考文档租户实例串流前获取设备的device_token。
- 应用墙MainActivity显示应用列表。
查询云机中已安装的应用列表,与本地缓存或数据库保存的应用白名单匹配,取并集后把应用列表显示到应用墙上。
- 调用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。
- 打开串流应用。
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;//云机服务忙
- 调用SDK接口可以获取云机已经安装的应用列表。