您尚未登录

登录

推荐您使用PC浏览器访问

确定
  • 开发者中心
  • >
  • 云手机
  • >
  • 技术文档
  • >
  • Android

云手机SDK开发指南

修改历史

版本 日期 主要作者
0.1 2017/09 SDK团队 初始文档
0.5 2018/03 SDK团队 支持清晰度切换API
1.0.0 2018/12 SDK团队 重构无UI版本
1.1.0 2019/05 SDK团队 支持清晰度切换;增加功能键发送

1 SDK集成准备

1.1 导入SDK

将我们提供的SDK压缩包中libs目录下的aar文件拷贝到你工程的app/libs目录下,并在app Module的build.gradle文件中,添加repositories和dependencies,并且添加所需依赖库,如下所示:

repositories {   
  flatDir {     
   dirs 'libs'   
     } 
   }
   dependencies {   
   compile 'com.android.volley:volley:1.1.0'   
   compile 'com.alibaba:fastjson:1.2.0'   
   compile (name: 'saas-sdk-v1.0', ext: 'aar') 
   }

注:

1.海马云手机客户端SDK目前只支持通过Gradle集成SDK的集成方式。

2.其中saas-sdk-v1.0是海马的sdk,其他为海马sdk用到的包。如果无法正常集成,请在Project的build.gradle文件中配置repositories,使用jcenter,如下所示:

allprojects {   

  repositories {    

​     jcenter()   

   } 

}

1.2 配置权限

在工程AndroidManifest.xml文件中添加如下权限:

<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> 
<uses-permission android:name="android.permission.READ_PHONE_STATE"/>

注:

1.andriod 6.0之后,权限获取有所变动,请参考官网:https://developer.android.com/training/permissions/requesting.html

2.小技巧:当xml中的targetSdkVersion=x(x<23)时候, 可以正常获取信息(相当于跳过了6.0权限检查)

1.3 配置硬件加速

打开硬件加速可以提高渲染能力,提高用户体验。

<application ……  
   android:hardwareAccelerated="true">

1.4 配置渠道信息

渠道信息包括以下两个字段:

HMCP_ACCESS_KEY_ID //接入商的唯一ID,用来区分不同的接入商。该值由海马云分配。

HMCP_CHANNEL_ID //渠道号,由接入商配置。如果应用本身不区分渠道,可以设置为一个随机值的的字符串。

这两个参数需要写在AndroidManifest.xml中,代码示例如下:

<meta-data android:name="HMCP_ACCESS_KEY_ID" android:value="海马商户分配的id" />
<meta-data android:name="HMCP_CHANNEL_ID" android:value="渠道id" />

1.5 代码混淆

如果你的apk最终会经过代码混淆,请在proguard配置文件中加入以下代码:

-dontwarn org.codehaus.**
-keep class org.codehaus.** {*;}
-keep interface com.haima.hmcp.listeners.*{*;}
-keep class com.haima.hmcp.beans.*{*;}
-keep enum com.haima.hmcp.enums.*{*;}
-keep class com.haima.hmcp.**{*;}
-keep enum com.haima.hmcp.websocket.WebSocketCloseNotification{*;}
-keep interface com.haima.hmcp.websocket.WebSocket{*;}
-keep interface com.haima.hmcp.websocket.WebSocketConnectionObserver{*;}
-keep class com.haima.hmcp.websocket.WebSocketConnection{public 
<methods>;}
-keep class com.haima.hmcp.websocket.WebSocketOptions{public <methods>;}
-keep class com.haima.hmcp.websocket.WebSocketException{*;}
-keep interface com.hmcp.saas.sdk.listeners.*{*;}
-keep class com.hmcp.saas.sdk.beans.*{*;}
-keep class com.hmcp.saas.sdk.enums.*{*;}
-keep class com.hmcp.saas.sdk.SaasSDK{public <methods>;}
-keep class de.tavendo.autobahn.**{*;}
-keep class tv.haima.ijk.media.player.** { *; }
-keep interface tv.haima.ijk.media.player.listeners.*{*;}
-keep interface tv.haima.ijk.media.player.IMediaPlayer{*;} 
-keep class com.netease.LDNetDiagnoService.LDNetDiagnoService{public <methods>;}
-keep interface com.netease.LDNetDiagnoService.LDNetDiagnoListener{public <methods>;}
-keep class com.netease.LDNetDiagnoService.LDNetTraceRoute { *; } 
-dontwarn org.openudid.**
-keep class org.openudid.**{*;}

2 SDK集成

2.1 Layout中布局组件

在布局文件中添加CloudPhoneVideoView组件

<com.haima.hmcp.widgets.CloudPhoneVideoView   

android:id="@+id/gameView"   

android:layout_width="match_parent"   

android:layout_height="match_parent" />

CloudPhoneVideoView组件所在Activity需要以下属性

<activity   

android:name=".xxxActivity"   

android:configChanges="orientation|screenSize"   

android:launchMode="singleTask"   

android:screenOrientation="landscape" />

2.2 Activity中初始化组件

以下是Activity中的示例代码,并且做了注释,后面还有详细的解释。

import com.haima.hmcp.widgets.*;

import com.haima.hmcp.listeners.*;

import com.haima.hmcp.enums.*;

import com.haima.hmcp.beans.*;

import com.haima.hmcp.utils.*;


public class HmcpPlayerActivity extends AppCompatActivity implements 
HmcpPlayerListener {

  @Override

  Protected void onCreate(Bundle savedInstanceState) {

  //获取组件

  CloudPhoneVideoView VideoView= (CloudPhoneVideoView) this.findViewById(R.id.gameView);

}

  //Activity需要implements HmcpPlayerListener接口

​    @Override

  public void onError(ErrorType errorType, String s) { // 出错信息回调

  }

  @Override

  public void onSuccess() { // SDK启动成功并且开始播流的回调

  }

  @Override

  public void onExitQueue() {

​    this.finish(); // 内部弹窗退出回调

  }

  @Override

  public void onMessage(Message message) { // 收到退出登录消息回调

  }

  @Override

  public void onSceneChanged(String s) { // 收到场景切换的回调

  }

  @Override

  public void onNetworkChanged(NetWorkState state) { // ⽹络发⽣变化时的回调。

  }

  @Override

  public void onPlayerError(String errorCode, String errorMsg) {

  }

  @Override

  public void onPlayStatus(int status, long value, String data) {

  }

  @Override

  public void HmcpPlayerStatusCallback(String callback) {

  }

  @Override

  public void onInputMessage(String msg) {

  }

 //Activity部分方法的重写

  @Override
  protected void onResume() {
    super.onResume();
    videoView.onResume();
  }
  @Override

  protected void onPause() {
    super.onPause();
    videoView.onPause();
  }
  @Override
  protected void onDestroy() {
    super.onDestroy();
    if (videoView != null) {
      videoView.disconnect();
    }
  }

}

注:

1.Activity的onResume(),onPause(),onDestroy()必须重写,并在重写的方法中调用CloudPhoneVideoView的相应方法,实现可以参考上面的代码。

2.Activity需要实现 HmcpPlayerListener的接口,包括:

● onError(ErrorType type, String errorInfo) 是连接云手机失败后的回调,可以通过errorInfo弹出提示信息;

● onSuccess(),连接云手机成功后回调。

● onExitQueue()是退出云手机时的回调,需要在该回调内调用finish()退出Activity。

● onMessage(Message message)是SDK的消息通知回调。

● onSceneChanged(String sceneMessage)是SDK使用云手机过程中各状态发生变化时通知应用的接口,sceneMessage是包括sceneId和extraInfo{}两个字段的JSON串。详细请参考“参数说明”中的“场景切换”章节。

● onNetworkChanged(NetWorkState state)是SDK在监听到网络变化后通知应用的接口,NetWorkState为enum类型,现在包括ISWIFI,NOTWIFI,NO_NETWORK三种。

声明:上述所有接口全部需要在Activity的Context里执行,也就是在主线程中执行,不需要调用runOnUiThread,或者post之类的方法。

2.3 开始使用云手机

调用CloudPhoneVideoView的connect()函数,SDK会与海马云的server通讯,申请服务成功后云手机的桌面会显示在CloudPhoneViewView组件上。

代码示例如下:

UserInfo userInfo = new UserInfo();

userInfo.userId = "";

userInfo.userToken = "";

videoView.setUserInfo(userInfo);


Bundle bundle = new Bundle();

bundle.putString(CloudPhoneVideoView.PHONE_ID, phoneId);

bundle.putString(CloudPhoneVideoView.ACCESS_KEY_ID, accessKeyId);

bundle.putString(HmcpVideoView.EXTRA_ID, "cloudPhoneDemo");

bundle.putSerializable(CloudPhoneVideoView.SCREEN_ORITENTION, ScreenOrientation.PORTRAIT);

bundle.putString(CloudPhoneVideoView.TOKEN, token);


videoView.connect(getApplicationContext(), bundle, new OnInitCallBackListener() {

  @Override

  public void success()

  {

​    Log.d(TAG, "InitCallback success");

  }



  @Override

  public void fail(String msg)

  {

​    Log.e(TAG, "InitCallback fail: " + msg);

  }

});

各参数定义如下:

● phoneId: 申请云手机时服务器返回的唯一标识符。

● accessKeyId:渠道信息。

● Orientaion::标识云手机是竖屏显示还是横屏显示。

● token:用来校验参数的有效性,token的生成请参考服务端SDK文档或者联系我们获取生成方法。

● videoView: 云手机显示组件。

● OnInitCallBackListener:回调接口,用于返回云手机的连接状态。

2.4 停止使用云手机

停止使用云手机只是断开与远程云手机的连接,云手机还将继续工作,客户端还可以再次连接并且正常使用。

有两种方式停止使用云手机:

1.连续点击两次返回键退出

这种方法退出需要app在Activity重载onPause(),onDestroy(),重载可以参考以下代码

@Override
protected void onPause() {
  super.onPause();
  videoView.onPause();
}
@Override
protected void onDestroy() {
  super.onDestroy();
  if (videoView!= null) {
    videoView.disconnect();
  }
}

2.5 获取清晰度列表

videoView.mResolutionList; //获取清晰度列表

2.6 切换清晰度

videoView.switchResolution(String resolution);  //resolution:要切换到的清晰度ID

2.7 发送功能键

videoView.onButtonClick(KeyEvent.KEYCODE_HOME); //发送HOME键videoView.onButtonClick(KeyEvent.KEYCODE_BACK);  //发送返回键videoView.onButtonClick(KeyEvent.KEYCODE_MENU); //发送MENU键

3 参数说明

3.1 场景切换

使用云手机过程中的各个状态切换都会通过onSceneChanged(String sceneMessage)接口通知应用,sceneMessage字符串是有JSON串转换的,格式如下:

{

“sceneId”: “” , //切换到的场景Id

“extraInfo” {} , //场景切换的扩展信息,参考sceneId说明

}

以下是使用过程中个状态的sceneId及描述:

名称 sceneId extraInfo{} 备注
onSceneChanged应用场景切换详细信息 init 初始化中,extraInfo为空
wait 排队中,extraInfo为空
play 开始使用,extraInfo为空
stop 使用结束,extraInfo参考参数示例
mait 云玩维护,extraInfo参考参数示例
crtp 显示自动降低码率tips,extraInfo参考参数示例
crst 开始切换码率(当前码率,目标码率,自动手动模式),extraInfo参考参数示例
cred 切换码率完成(成功,失败,当前码率),extraInfo参考参数示例

以下是使用云手机过程中各状态对应的扩展信息extraInfo{}描述:

“init” : 初始化中, extraInfo 为空

“wait” : 排队中, extraInfo 为空

“play” : 开始使用, extraInfo 为空

“stop” : 使用结束

​ “extraInfo” : {

​ “interval” : 当次使用时长,单位 秒

​ “reason” : “time_limit” :当次时间到

​ “no_operation” :超时无操作

​ “instance_err” :实例出错

​ “forced” :强制下线

​ “token_expire” :Token失效

​ “log_off” :注销

​ “network_off” :网络不可用

​ “request_err” :网络请求出错

​ }

“mait” : 云玩维护

​ “extraInfo” : {

​ “progress” : “soon” :即将

​ “start”:进入

​ “done” :恢复

​ }

“crtp” : 显示自动降低码率tips

​ “extraInfo” : {

​ “minimum” : 当前码率是否最低码率 “0”-否 “1”-是

​ }

“crst” : 开始切换码率 (当前码率,和目标码率,自动手动模式)

​ “extraInfo” : {

​ “source” : “” 当前码率

​ “des” : “” 目标码率

​ “method” : 自动手动模式 “0”-手动 “1”-自动

​ }

“cred” : 切换码率完成 (成功,失败,当前码率)

​ “extraInfo” : {

​ “result” :”0”-失败 “1”-成功

​ “cur_rate” :当前码率

​ }

4 注意事项

4.1 安卓5.0+系统需要手动申请权限,申请权限代码如下:

private void requestCloudSdkPermission() {
  if (Build.VERSION.SDK_INT >= 23 && ContextCompat.checkSelfPermission(this, Manifest.permission.READ_PHONE_STATE) != PackageManager.PERMISSION_GRANTED) {
    String[] mPermissionList = new String[]{Manifest.permission.READ_PHONE_STATE};
    ActivityCompat.requestPermissions(CloudPlayActivity.this, mPermissionList, 100);
  } else {
    // 不需要什么权限
  }
}

4.2 关于部分手机虚拟键盘显示实效设置问题

Activity实现OnSystemUiVisibilityChangeListener, 并且重写onSystemUiVisibilityChange(int visibility)方法

在onCreate()方法中注册OnSystemUiVisibilityChangeListener,如下:

getWindow().getDecorView().setOnSystemUiVisibilityChangeListener(this);

重写onSystemUiVisibilityChange(int visibility)方法,如下:

@Override
public void onSystemUiVisibilityChange(int visibility) {
  setHideVirtualKey();
}

private void setHideVirtualKey() {
  //保持布局状态
  int uiOptions = View.SYSTEM_UI_FLAG_LAYOUT_STABLE |
      //布局位于状态栏下方
      View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION |
      //全屏
      View.SYSTEM_UI_FLAG_FULLSCREEN |
      //隐藏导航栏
      View.SYSTEM_UI_FLAG_HIDE_NAVIGATION |
      View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN;
  if (Build.VERSION.SDK_INT >= 19) {
    uiOptions |= 0x00001000;
  } else {
    uiOptions |= View.SYSTEM_UI_FLAG_LOW_PROFILE;
  }
  getWindow().getDecorView().setSystemUiVisibility(uiOptions);

}

4.3 推荐设置Activity界面为全屏沉浸式效果,在onCreate()方法中添加如下代码:

public static boolean setTranslucentStatus(Activity activity) {
  if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT && Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) { //4.4以上,状态栏透明
    activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
    return true;
  } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {//5.0以上状态栏透明
    Window window = activity.getWindow();
    window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
    window.getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
        | View.SYSTEM_UI_FLAG_LAYOUT_STABLE);
    window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
    window.setStatusBarColor(Color.TRANSPARENT);
    return true;
  }
  return false;
}
×

本篇文章对你是否有帮助?

更多建议

请输入您的建议