跳转至

安卓接入指南

集成依赖

moving_library-x.x.x.aar 文件复制到 app 项目的 libs 文件夹下。

然后,在 project 的 gradle 中添加:

buildscript {
     dependencies {
        // ...
        // 添加kotlin插件 sdk使用
        classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:1.5.10"
    }
}

app 的 gradle 中添加:

apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-android-extensions'

android {
    defaultConfig {
        ndk {
            abiFilters "armeabi", "armeabi-v7a"
        }
    }
}

repositories {
    // 如果项目类库的libs文件中有项目依赖的aar文件,需要添加此配置后再引入
    flatDir {
        dirs 'libs'
    }
}


dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])

    // 引入libs文件夹中的aar资源
    implementation(name: 'moving_library-2.0.0', ext: 'aar')
    // ...
}

上手使用

初始化

在 Application 中 onCreate 方法中添加初始化和配置代码:

        //初始化和配置SDK
        //建议在Application 的 onCreate方法中添加
        Moving.init(this)                                               //必选!初始化SDK
                .setWssConnectUrl(GameDefaultConfig.WSS_CONNECT_URL)    //可选 设置WebSocket服务器
                .setWssConnectTimeout(15*1000)                          //可选 设置WebSocket连接超时时间(毫秒)
                .setWssConnectionLostTimeout(60)                        //可选 设置WebSocket心跳间隔时间
                .setWssReconnectFrequency(60)                           //可选 设置WebSocket断开后的重连次数,可以设置的很大,不会有什么性能上的影响
//                .setDecodeType(MovingDecodeType.DECODE_SOFT)          //可选 设置强制软解硬解
                .setShowLog(true);                                      // 可选 设置是否显示日志

主页面逻辑实现

添加监听器

@Override
protected void onCreate(Bundle savedInstanceState){
    super.onCreate(savedInstanceState);
    // 添加监听器
    Moving.getInstance().addMovingListener(this);
}

移除监听器

@Override
protected void onDestroy() {
    super.onDestroy();
    // 移除监听器
    Moving.getInstance().removeMovingListener(this);
}

启动SDK

Moving
    .getInstance()
    .prepare2Start(
        new MovingPre2StartParam(startToken)
    );

实现监听器回调逻辑

    @Override
    public void onHandleMovingMessage(MovingListenerCode messageCode, String messageJson) {
        switch (messageCode) {
            case SDK_MIGRATE_ASK:// 询问迁移
                // 提醒 正在游戏中
                break;
            case SDK_AUTH_SUCCESS:// 鉴权成功
                break;
            case SDK_IN_THE_QUEUE:// 排队中
                // 提醒需要排队
                break;
            case SDK_QUEUE_CHANGE:// 排队状态改变
                // 提醒队列变化实现 排队位置在messageJson中
                break;
            case SDK_PREPARE_SUCCESS:// 准备成功,可以开始游戏
                // 开始游戏按钮设为可用状态
                break;
            default:
                break;
        }
    }

游戏界面逻辑实现

添加游戏组件

在游戏界面xml布局文件中添加游戏界面组件:

<com.tingyutech.movingsdk.views.MovingGameView android:id="@+id/mMovingGameView"
    android:layout_width="match_parent" android:layout_height="match_parent"
    app:Moving_inputMode="cursor" app:Moving_isShowDebugInfo="true" />

其中自定义属性参考如下:

  • app:Moving_isShowDebugInfo 为是否展示调试文本信息,默认不展示
  • app:Moving_inputMode="cursor" 为设置虚拟输入空间,默认不使用虚拟输入组件
    • none: 不使用触屏模式输入模式
    • cursor: 使用触屏鼠标模式
    • handle: 使用触屏手柄模式

继承 MovingGameActivity 并复写抽象方法

提示

完成 UI 初始化部分后,需要主动调用父类的 startGame(startToken); 方法才会开始游戏。

public class GameActivity extends MovingGameActivity {
    // 游戏界面组件,需要在getMovingGameView()方法中返回
    MovingGameView mMovingGameView;

    @Override
    protected int getContentLayoutId() {
        MyApplication.setGameViewStyle(this);   // 设置Activities样式
        // 第一步:设置UI布局
        return R.layout.activity_custom_game;
    }

    @Override
    protected void initUIViews(Bundle savedInstanceState) {
        // 第二步:初始化游戏组件
        mMovingGameView = findViewById(R.id.mMovingGameView);

        // 测试游戏界面组件能力
        findViewById(R.id.mSettingButton).setOnClickListener(v -> showOptionMenuDialog());

        // Demo中是从Demo服务器获取开始方法需要的参数 startToken
        // 此方法调用之后才会开始游戏,开始游戏时需要传入 startToken
        startGame(startToken);
    }


    @Override
    protected MovingGameView getMovingGameView() {
        // 第三步:设置游戏组件
        return mMovingGameView;
    }

    @Override
    protected void onGameStop() {
        EasyToast.getDEFAULT().show("游戏结束,自动关闭游戏页面");
        // 如果需要拦截游戏结束后自动关闭页面,可把super的调用删掉即可
        super.onGameStop();
    }

    @Override
    protected void getRenewToken(String deadline, @NonNull RenewTokenDeadlineListener renewTokenDeadlineListener) {
        // Demo中是从Demo服务器获取开始方法需要的参数 RenewToken
        // ...
        // 更新RenewToken
        renewTokenDeadlineListener.refreshRenewToken(RenewToken);
    }

//    @Override
//    protected boolean onBack2StopGame() {
//        // 此处可以返回true来拦截默认的退出游戏事件
//        return false;
//    }
//
//    @Override
//    protected boolean onError2StopGame() {
//        // 此处可以返回true来拦截默认的退出游戏事件
//        return false;
//    }
}

游戏界面高级功能使用

动态切换输入组件

// 不使用任何触屏虚拟输入
mMovingGameView.setTouchInputMode(MovingGameView.INPUT_MODE_NONE);

// 使用触摸光标模式
mMovingGameView.setTouchInputMode(MovingGameView.INPUT_MODE_CURSOR);

// 使用虚拟手柄模式
mMovingGameView.setTouchInputMode(MovingGameView.INPUT_MODE_HANDLE);

使用自定义触屏虚拟组件

// 可选,使用自定义虚拟鼠标组件,不设置则使用默认组件
mMovingGameView.setCursorView(new MyCursorView(GameActivity.this));
// 可选,使用自定义虚拟手柄组件,不设置则使用默认组件
mMovingGameView.setHandleView(new MyHandleView(GameActivity.this));
// 自定义组件不支持xml中配置模式,xml中配置的输入组件类型使用的是默认组件样式
// 如果使用自定义组件,设置自定义组件后需要主动刷新一次或者调用动态切换组件的方法setTouchInputMode()
mMovingGameView.refreshTouchInputMode();

清空自定义触屏虚拟组件

清空自定义组件与使用自定义组件类似,需要清空哪个,哪个设置为空即可

// 可选,清空自定义虚拟鼠标组件
mMovingGameView.setCursorView(null);
// 可选,清空自定义虚拟手柄模式
mMovingGameView.setHandleView(null);
// 清空自定义组件后需要主动刷新一次或者调用动态切换组件的方法setTouchInputMode()
mMovingGameView.refreshTouchInputMode();

视频等级修改参数

视频等级修改参数。通过 displayGrade 接口获取

Moving.getInstance().setServiceLevel("需要设置的质量参数");

交互时序图

如下是 SDK 和客户端 APP 的简要交互时序图,请参考该图接入 SDK 业务。

sequenceDiagram Client->>+SDK: 初始化(传 authToken) SDK-->>Client: 认证成功 opt 确认迁移 Note over Client,SDK: 当前用户已有会话,需要确认是否连接<br>如果确认,直接开始游戏即可 SDK->>Client: 询问迁移 end opt 等待排队 Note over Client,SDK: 当前需要排队 SDK->>Client: 提示需要排队 opt 排队位置更新 SDK->>Client: 更新队列位置 end SDK->>Client: 排队完成 end deactivate SDK Note right of Client: 不管是用户已有会话,<br>还是排队完成或者不需要排队,<br>都要手动调用开始游戏。 Client->>+SDK: 开始游戏(传startToken) SDK->>Client: 进度 20% SDK->>Client: 进度 30% SDK->>Client: 进度 60% SDK->>Client: 进度 95% SDK->>-Client: 游戏启动成功 loop renewToken SDK->>+Client: 请求 renew token Client-->>-SDK: 返回 end opt 画质切换 Client->>+SDK: 画质切换{grade} SDK->>-Client: 设置成功 end opt 手动结束游戏 Client->>SDK: 结束游戏 end opt 被动结束游戏 SDK->>Client: 游戏被结束事件{code, reason} end

sequenceDiagram participant 客户端 participant MovingSdk 客户端->>MovingSdk:Application onCreate()中初始化 init(this) 客户端->>客户端:进入开始界面 Note right of 客户端:开始页面 onCreate中 添加SDK监听器 addMovingListener(this)<BR>实现接口 MovingListener onHandleMovingMessage方法;在此方法中监听MovingSdk的回调事件<BR>onDestroy中 添加SDK监听器 removeMovingListener(this) Note right of 客户端:获取AuthToken 客户端->>MovingSdk:尝试开始游戏 prepare2Start(new MovingPre2StartParam(AuthToken)) MovingSdk-->客户端: SDK_MIGRATE_ASK 询问迁移 MovingSdk-->客户端: SDK_IN_THE_QUEUE 排队中 MovingSdk-->客户端: DK_QUEUE_CHANGE 排队状态改变 MovingSdk-->客户端: SDK_PREPARE_SUCCESS 准备成功,可以开始游戏 Note left of MovingSdk: 如需更多详细回调,请查看【监听参数说明】相关内容 客户端->>客户端:进入游戏界面 Note right of 客户端:继承 MovingGameActivity 实现抽象方法 MovingSdk-->客户端: getContentLayoutId() 获取layout id MovingSdk-->客户端: initUIViews() 初始化组件MovingGameView组件 MovingSdk-->客户端: getMovingGameView() 返回初始化的getMovingGameView组件实例 Note right of 客户端:获取StartToken 调用父类 startGame(StartToken) MovingSdk-->客户端: getRenewToken(String deadline, @NonNull RenewTokenDeadlineListener renewTokenDeadlineListener) 更新RenewToken Note right of 客户端:如果调用getRenewToken 后10秒还为收到客户端的token 更新(RenewTokenDeadlineListener.refreshRenewToken)<BR>则再次调用getRenewToken<BR>最多循环3次,3次超时后不再调用getRenewToken 客户端->>MovingSdk: 更新RenewToken renewTokenDeadlineListener.refreshRenewToken(RenewToken)