该文档介绍了如何通过下载补丁包然后动态加载(热更新)的方式实现微端包到完整包的转化,并且还实现了登录/支付的穿透。
微端涉及的模块和关系如下。 其中,您只需要实现游戏APK(生成补丁包)、微端APK、云端APK,其他模块由腾讯云提供。
模块 | 说明 |
---|---|
游戏APK | 游戏APK,可以是任意安装包,用于生成补丁包。是微端APP热更新升级后的目标APP。 |
微端APK | 微端APK,集成了微端SDK,是用于广告投放的包体,供C端用户玩云游戏的载体。 |
云端APK | 云端APK,集成了云端SDK,运行于云端,是C端用户在微端上玩的云游戏。 |
补丁包 | 补丁包,由游戏APK经过工具一键转化生成。微端APK在运行时从网络下载补丁包,动态加载后进行热更新,从而升级为完整本地游戏。 |
微端SDK | 微端SDK,集成了云游戏终端SDK和热更新SDK,实现了微端的应用逻辑,包括云游戏试玩,云端数据通道交互,补丁包的检查、下载、校验、合成,下载智能限速等交互逻辑。 |
云游戏终端SDK | 云游戏终端SDK,是云游戏PAAS平台提供的终端SDK,它实现了云游戏在终端上的通用功能,方便快速构建云游戏终端APP。 |
热更新SDK | 热更新SDK,实现热更新机制,包括补丁包处理合成、加载逻辑。实现微端APP转化为本地游戏。 |
云端SDK | 云端SDK,提供云端与终端数据通道能力,用于实现APP的登录和支付穿透的功能。 |
微端云游戏后台 | 微端云游戏试玩的业务后台,调用云游戏PAAS平台的后端API,实现云试玩的业务层逻辑。 |
整体接入和运行流程如下
备注:如果您是游戏发行商角色,没有游戏工程源码,但是游戏APK里有集成了你的登录支付SDK,那么你也可以独立完成接入云端SDK生成云端APK,而无需游戏研发团队的介入。
微端接入优势
-
一站式便捷接入。
流程极简,提供完备的SDK/Demo/工具,一次接入多个游戏复用。
-
投放包体极小。
10M左右,提升投放效果,降低买量成本。
-
原生游戏体验。
依赖于腾讯云渲染技术,云游戏体验接近本地游戏。本地原生的登录支付体验。
-
边玩边下。
试玩云游戏的过程中静默下载补丁包,智能限速,不影响云游体验。
-
免安装静默升级。
下载完补丁包后,免安装静默转化为本地游戏,用户无感知。
登录穿透的逻辑流程是:
(1)微端APP调用本地的登录SDK完成本地登录过程,将获取到的登录授权信息,通过数据通道发送给云端APP。
(2)云端APP收到微端发送的登录授权信息,完成云端APP的登录交互。
支付穿透的逻辑流程是:
(1)云端APP将支付请求,通过数据通道发送给微端APP。
(2)微端APP调用本地的支付SDK完成支付,将支付结果信息再通过数据通道发送给云端APP。
(3)云端APP使用这个信息完成云端APP的支付交互。
其中,需要注意以下几点,
(1)由于云端app会提前预加载,微端连接之前数据通道无法使用。
(2)使用数据通道之前,必须由微端先发送消息给云端app,才能正常建立通信,详情参考3.3.3 实现登录/支付穿透逻辑。
云试玩的逻辑流程是:
(1)客户部署云端app到腾讯云服务器中,服务器创建多个实例预加载云端app等待微端app连接。
(2)微端app通过微端sdk连接在云端已经预加载成功的云端app实例,并通过数据通道同步两者的状态。
其中,需要注意以下几点,
(1)预加载是指云端app已经在服务器中提前被打开,而不是微端app打开时才打开云端的app。
(2)微端app每次连接一个新的云端app实例,所以需要保存的数据需要通过数据通道保存到微端app。
(3)云试玩体验建议使用真机,模拟器系统存在不确定性,会影响云游戏的体验。
(4)热更新的静默转化并不是将部署到云端的app转化到本地,而是加载正常游戏包生成的补丁包来实现完整游戏的转化。
热更新的逻辑流程是:
(1)微端app在运行过程中去客户配置的补丁包链接中下载该微端包可用的补丁。
(2)下载成功后通过微端sdk的能力加载该补丁包完成到完整游戏的转化。
(3)热更新完成后,重启微端app进入完整游戏逻辑。
如果不需要实现登录支付穿透,可以直接把游戏apk给到对接群的同事,部署到云端获取gameId即可完成游戏体验。
如果需要实现登录支付穿透,请按照以下步骤修改游戏APP,将其转化为云端包,
demo中接入了微信登录的功能,以下步骤展示了如何改造游戏包的微信登录部分,使其能够配合在本地运行的微端包完成登录支付穿透,
微端包登录/支付穿透的修改参考3.3.3 实现登录/支付穿透逻辑。
第一步,集成云端SDK。打开游戏原始包工程,在app/build.gradle文件中添加云端SDK依赖。
dependencies {
implementation "com.tencent.tcr:micro-cloud-sdk:2.0.1"
}
云端sdk的具体使用方法请参考云端SDK的API文档,同时云端包的适配可以参考云端APP示例工程.
第二步,建立数据通道,实现登录/支付穿透的具体逻辑。
1)建立数据通道,开始监听微端发送的数据。监听的代码如下:
DataChannel.Listener listener = new DataChannel.Listener() {
public void onReceive(byte[] buffer, int len) {
// 从监听的端口接收到数据
String dataFromRemote = new String(buffer, 0, len);
// 微端传递的是json格式的数据,所以转为JSONObject易于操作,不以json格式传输也可以
JSONObject receiveData = new JSONObject(dataFromRemote);
// 收到微端发送的消息证明数据通道已经连接成功
isConnectSuccess = true;
// 只有在收到微端发送的{"connected":true}消息之后,才能向微端发送消息
// 因为云端包对应的实例会提前在云服务器中启动,等待微端的连接,微端未连接之前都是无法通信的。
if (!receiveData.isNull("connected") && receiveData.getBoolean("connected")) {
// 微端和云端的数据通道已经连接成功了,此时可以向微端发送登录请求。
// 登录穿透修改:将游戏中原先触发登录弹窗的逻辑删除,并向微端发送登录消息,让弹窗在微端收到login消息之后再弹出
// 云端包示例工程只是为了演示才在收到{"connected":true}消息之后向微端包发送“login”消息,实际开发过程中发送“login”消息只要保证isConnectSuccess为true即可,具体的交互逻辑可以自定义。
sendData("login");
}
// 收到微端login之后的结果,获取到登录用户的信息即可执行之后的逻辑。
if (!receiveData.isNull("authCode")) {
// 登录穿透修改:继续执行之前在游戏工程中获取authCode之后的逻辑
// 不同的登录sdk在此处的处理逻辑有所不同,可以参考微信登录的流程
WXBiz.getInstance().getToken(receiveData.getString("authCode"));
}
}
public void onException(Exception e) {
// 数据接收或发送过程中出现异常
}
};
// 建立并打开数据通道,开始监听
mDataChannel = new DataChannel(listener, 6666);
mDataChannel.open();
这部分的详细代码在云端APP示例工程的TcrMicroCloud/src/main/java/com/DefaultCompany/Unity2018Empty/DataChannelService.java类中。
登录穿透是将“直接拉起本地登录软件进行登录”改为“通过数据通道拉起微端所在设备的登录软件进行登录”。
主要演示了云端APP如何与微端APP通过数据通道建立联系,可以对比游戏APP示例工程的代码,在适配云端登录穿透时,需要删除游戏工程中弹出登录弹窗部分的逻辑,
删除之后,通过数据通道发送“login”消息给到微端APP,微端APP收到该消息之后在本地再弹出登录弹窗。
微端APP在完成微信登录的授权获取到authCode时,再通过微端sdk提供的发送消息接口将authCode发送给云端包,云端包收到authCode后继续执行之后的逻辑来获取用户信息。
支付穿透的逻辑和登录一致,也是需要将“直接拉起本地支付软件进行支付”改为“通过数据通道拉起微端所在设备的支付软件进行支付”。
2)在需要数据交换时通过数据通道向微端发起对应消息。
云端发送的限制是65536的字符,微端发送数据的限制是1200字符。如果发送数据大于发送限制,需要考虑将数据分段进行发送,所以尽量保证数据通道不要传输大型数据。
/**
* 通过此方法向发送方回复数据
* 必须在数据通道连接成功后使用
* 该方法必须在非UI线程中调用。
*
* @param data 要发送的数据
*/
public void sendData(String data) {
if (mDataChannel != null) {
mDataChannel.send(data.getBytes(Charset.forName("UTF-8")));
}
}
注意:云端包发送数据必须在云端包收到微端发送的消息之后,这样云端才能确认是和哪个微端进行通信,同时发送数据的操作不能在子线程中执行。
第三步,云端APK的本地调试。
云端包需要部署到腾讯云服务器上才可以接收到微端包发送的数据,部署游戏相对比较复杂。因此需要在部署之前在本地测试云端APK的数据通道的功能是否符合预期,测试方法如下:
下载数据通道测试APP,解压之后通过AndroidStudio打开。模拟微端包发送数据,代码如下:
private void sendDataToCloud(String testData) {
Log.d(TAG, "sendDataToCloud: " + testData);
try {
InetAddress address = InetAddress.getByName("localhost");
byte[] buf = testData.getBytes(StandardCharsets.UTF_8);
DatagramPacket sendPacket = new DatagramPacket(buf, buf.length, address, 6666);
socket.send(sendPacket);
} catch (IOException e) {
e.printStackTrace();
}
}
云端包安装到手机上会开启一个udp端口,测试APP的逻辑就是模拟云端容器向云端app的数据通道端口发送数据。
先在手机上打开云端包,然后按home键回到桌面,再打开测试APP,点击test按钮向安装在本地手机上的云端APP发送测试数据,过滤云端APP的相关log标签查看是否成功收到测试APP发送的数据。
第四步,将云端APK部署到腾讯云服务器。
本地调试成功之后,将该apk给到腾讯云对接的工作人员,待游戏部署成功后向工作人员获取游戏ID。
第一次部署apk需要工作人员协助,之后调试过程中需要更新云端apk,可以申请自助替换云端apk。
安装java11环境。下载微端APP示例工程,解压后,在Terminal中进入到hotUpdate目录下,执行以下脚本:
./generate_patch.sh 游戏APK路径
该脚本命令将根据游戏APK生成对应的补丁包,存放在:hotUpdate/out/patch.apk。
此步骤会根据游戏apk自动生成的壳子四大组件,并把自动生成的壳子组件拷贝到微端工程的app/src/main/java中。
微端APP下载完补丁包后,免安装静默转化为本地游戏,是通过热更新技术实现的。您可以下载微端体验apk体验静默转化的效果。
为了实现热更新,微端APK需要依赖游戏APK的R.txt文件和AndroidManifest.xml文件。AndroidManifest.xml文件是为了保证游戏APK里的Application、四大组件和权限声明在微端APK里有向系统注册。R.txt文件是为了保证AndroidManifest.xml文件里引用到的资源ID在微端APK和游戏APK里是一样的,避免热更新后发生资源引用的错误。
1、下载微端APP示例工程,解压并导入到AndroidStudio。
2、通过游戏APK获取R.txt文件。
在Terminal中进入到微端工程的hotUpdate目录下,使用以下命令生成R.txt:
./generate_resource_id.sh 游戏APK路径
该脚本主要通过aapt2命令提取游戏原始apk中的资源名称和ID,最终生成R.txt。
R.txt文件生成路径为:hotUpdate/out/R.txt。
注意:在windows上使用需要修改为windows的调用方式,如何修改请查看脚本。
3、通过游戏APK获取AndroidManifest.xml文件。
在Terminal中进入到工程的hotUpdate目录下,使用以下命令生成AndroidManifest.xml:
./generate_manifest.sh 游戏APK路径
该脚本主要通过apktools反编译获取游戏原始apk的AndroidManifest.xml文件。
AndroidManifest.xml文件生成路径为hotUpdate/out/AndroidManifest.xml。
同时还会生成存放游戏apk资源的game目录,方便之后使用。
第一步,修改构建脚本。
打开微端工程app模块下的build.gradle文件,修改applicationId、minSdkVersion、targetSdkVersion与您的游戏工程一致。
defaultConfig {
// 应用名称和您的游戏包名一致
applicationId "com.DefaultCompany.Unity2018Empty"
// 与你的游戏版本保持一致
minSdkVersion 21 // 微端SDK最低支持到16
//noinspection ExpiredTargetSdkVersion,OldTargetApi
targetSdkVersion 29 // 与你的游戏版本保持一致
// 与你的游戏abi保持一致
ndk {
abiFilters 'armeabi-v7a', 'arm64-v8a'
}
...
}
修改签名文件与您的更新包工程一致。
signingConfigs {
release {
keyAlias "testres"
keyPassword "testres"
storePassword "testres"
storeFile file("keystore/micro.keystore")
}
}
第二步,修复清单文件中的编译错误。
在准备工作中会自动把游戏的清单文件文件拷贝到微端工程的app/src/main目录下。
在3.2构建补丁包中会自动生成游戏中的四大组件,并把生成的壳子四大组件自动拷贝到微端工程的app/src/main/java目录下,
自动生成的组件中的内容都是空的,作为壳子在安装微端apk时注册给系统,这样热更新之后就可以找到对应的组件了。
之后打开app/src/main/AndroidManifest.xm文件,会发现文件中会有编译错误,
请把缺失的style、string、xml等从hotupdate/game中拷贝到微端工程的对应目录中,
修复清单文件中的编译错误,拷贝时为了减少最终的微端apk体积,建议只将缺少的资源拷贝到微端app模块。
第三步,修改工程代码。
将UnityPlayerActivity里的代码拷贝到新AndroidManifest.xml文件里带有"android.intent.action.MAIN"的主Activity类里,并把UnityPlayerActivity类删掉。
第四步,修改工程配置。
打开工程assets下的microSettings.xml,修改对应参数:
<?xml version="1.0" encoding="utf-8"?>
<settings>
......
<!-- 是否使用热更新的方式进行升级转化。 -->
<setting key="hot_update" value="true" />
<!-- 补丁包的地址。仅在hot_update为true的情况下才有意义。 -->
<setting key="patch_url"
value="https://cg-sdk-1258344699.cos.ap-nanjing.myqcloud.com/micro/patch/TcrMicroAppForUnity2018Empty/patch.apk" />
<!-- 游戏包的地址。配置之后,热更新失败会跳到浏览器去下载完整游戏apk -->
<setting key="apk_url" value="https://cg-sdk-1258344699.file.myqcloud.com/test/test.apk" />
</settings>
1、在配置文件patch_url中填写patch文件的下载链接,可以选择自己维护这个链接。
2、在配置文件apk_url中填写游戏官方包的下载链接,热更新失败会跳到浏览器去下载完整游戏apk。
第五步,构建生成微端apk后,在Terminal中进入到hotUpdate目录下,使用以下命令校验微端包:
./check_old_config.sh 微端apk路径 游戏APK路径
该脚本检查微端apk的清单文件是否和游戏原始apk一致,并输出检查结果。
可以正常校验通过没有ERROR信息即为正常。校验结果将生成到hotUpdate/check_result目录下。
校验失败请检查第二步操作是否正确。
第六步,本地调试验证。
注意:热更新调试验证建议使用真机进行测试。
在Terminal中进入到hotUpdate目录下,使用以下命令进行本地调试:
./local_debug.sh 微端apk路径 补丁包路径
该脚本将生成的补丁包通过adb命令push到手机的Download目录下,并通过adb卸载之前的微端包,安装新的微端包。
注意:需要先adb连接要调试的设备,修改脚本中要卸载微端的包名为当前微端的包名。
在手机上点击刚安装的apk,运行之后会提示“检测到本地补丁包“的弹窗,点击“加载补丁”选取刚才push到sd卡Download中的补丁文件,选择完毕后悬浮球显示更新中,更新完成弹出“重启弹窗”,点击“立即重启“按钮,查看是否可以正常重启。
第七步,本地调试验证成功后,删除sd卡Download中的补丁文件,并将补丁包上传到第四步的下载地址中开始验证。
第一步,通知云端APP,数据通道已连接成功。
public class UnityPlayerActivity extends MicroBaseActivity {
private boolean isConnectSuccess = false;
......
@Override
protected void onDataChannelConnectSuccess() {
// 这个回调是告诉微端APP,当前数据通道是可用状态
// 必须向云端游戏发送一条信息,告诉云端微端此时已经连上了,云端在收到这条消息之后才能进行数据传输
// 这条消息可以是自定义的任何消息
isConnectSuccess = true;
setDebugMode(true);
sendConnectMsg();
}
//向云端发送连接成功消息
private void sendConnectMsg() {
Log.d(TAG, "sendConnectMsg");
try {
JSONObject jsonObject = new JSONObject();
jsonObject.put("connected", true);
sendDataToCloudGame(jsonObject.toString());
} catch (Exception e) {
Log.e(TAG, "sendConnectMsg exception, " + e.getMessage());
}
}
private void setDebugMode(boolean isDebug) {
Log.d(TAG, "setDebugMode" + isDebug);
try {
JSONObject jsonObject = new JSONObject();
// 测试的云端apk中收到该字段为true,则会在云端将收到的信息通过Toast显示出来,方便调试
// 客户也可以在自己的云端包中新增一个类似的开关,把收到的微端包信息show出来
jsonObject.put("debug", isDebug);
sendDataToCloudGame(jsonObject.toString());
} catch (Exception e) {
Log.e(TAG, "sendConnectMsg exception, " + e.getMessage());
}
}
}
微端APP在收到微端SDK的onDataChannelConnectSuccess()回调之后,必须发送一条确认消息给云端APP(消息可以自定义),云端APP只有在收到这条确认消息之后才可以向微端APP发送消息。
使用setDebugMode设置调试模式,可以通过Toast的方式看到云端apk收到的微端消息,方便调试。由于云端游戏会提前预加载运行等待微端连接,所以在微端连接之前弹出的Toast都是无法被看到的,
这时候如果想要查看云端的运行情况,需要在对接群中联系后台开发同学帮忙抓取云端日志。
第二步,实现具体的登录支付逻辑。
微端APP示例工程中实现了微信登录穿透的逻辑,接下来介绍如果将微信登录获取到的授权信息传递给云端app,
public class UnityPlayerActivity extends MicroBaseActivity {
......
// 由于微信的授权信息在微信提供的WXEntryActivity中获取到的,因此这里使用了Activity之间的intent传递数据
// 具体可以参考app/src/main/java/com/DefaultCompany/Unity2018Empty/wxapi/WXEntryActivity.java中传递authCode的代码逻辑
@Override
protected void onNewIntent(Intent intent) {
Log.d(TAG, "onNewIntent: " + intent.getStringExtra("authCode"));
super.onNewIntent(intent);
// 在这里接收WXEntryActivity传递过来的authCode
if (intent.getStringExtra("authCode") != null) {
sendLoginCall(intent.getStringExtra("authCode"));
}
}
@Override
protected void onReceiveCloudGameMessage(String data) {
// 接收云端游戏的返回信息
if ("login".equals(data)) {
login();
} else if ("pay".equals(data)) {
pay();
}
}
// 处理支付操作
private void pay() {
Log.d(TAG, "pay: ");
// 支付部分逻辑与登录类似,可以参考登录部分传输逻辑。
}
// 处理登录操作
private void login() {
Log.d(TAG, "login: ");
// 本地弹出登录窗口
// 登录支付修改:弹窗的逻辑默认在游戏apk中,微端适配登录穿透之后需要在收到云端发送的“login”消息之后弹出
WXBiz.getInstance().showLoginDialog(this, new DialogClickListener() {
@Override
public void onPositiveClick() {
// 调用微信登录
WXBiz.getInstance().login();
}
@Override
public void onNegativeClick() {
finish();
}
});
}
// 获取到微信返回的authCode,通过数据通道传递给云端APP
// 登录原始逻辑:打开游戏弹出登录窗口->用户点击登录->拉起本地微信->授权成功,获取authCode->继续执行之后逻辑
// 登录穿透后:打开微端应用->进入云游戏->数据通道连接成功(onDataChannelConnectSuccess)->向云端发送{"connected", true}消息
// ->云端收到{"connected", true}->云端发送login消息->微端收到login消息弹出登录窗口->用户点击登录->拉起本地微信
// ->授权成功获取authCode->发送authCode到云端APP->云端APP收到authCode后,执行之后逻辑
public void sendLoginCall(String authCode) {
if (!isConnectSuccess) {
Log.d(TAG, "未连接成功,不能向云端发送登录回调");
return;
}
Log.d(TAG, "向云端发送登录回调");
try {
JSONObject jsonObject = new JSONObject();
jsonObject.put("authCode", authCode);
sendDataToCloudGame(jsonObject.toString());
} catch (JSONException e) {
Log.e(TAG, "sendLoginCall exception, " + e.getMessage());
}
}
}
第三步,微端包与云端包联调。
打开工程assets下的microSettings.xml,填入云端包的对应参数
<?xml version="1.0" encoding="utf-8"?>
<settings>
<!--云端包部署之后获取的游戏ID-->
<setting key="game_id" value="game-xxxxx" />
......
<!--与云端通信的端口号-->
<setting key="port" value="6666" />
......
</settings>
云端包部署之后会获取到对应的gameId,将该gameId填入到微端配置参数中,端口号为云端包建立数据通道时开启的端口号。
修改之后构建微端包,安装到手机并运行,验证登录/支付穿透流程是否正常。
适配完成后可以删掉用于演示用的登录穿透逻辑。
微端工程有一套默认的UI模块(micro-ui),其中包含各种提示弹窗、悬浮球、启动加载界面,如果您需要定制化自己的UI,可以根据自己需求进行更改。
背景图片替换:
替换micro-ui/src/main/res/drawable-xxhdpi/micro_loading.jpg该图片为您想要展示的图片。
启动界面显示效果:
除此之外,如果您想要修改进度条的显示效果,可以修改micro-ui/src/main/res/layout/micro_loading_view.xml来更改进度条的显示效果。
修改弹窗文字:
打开micro-ui/src/main/java/com/tencent/tcr/micro/MicroUISettings.java,
修改对应弹窗的文字提示和对应的按钮文字。
修改显示效果:
如果您需要定义自己的弹窗,可以根据需要修改弹窗的UI配置代码。
打开micro-ui/src/main/res/layout/micro_float_window.xml,修改悬浮球的界面效果。
数据通道需要在微端APP云游戏连接成功之后才可以正常使用,如果需要在数据通道连接之前向云端游戏传递数据,可以通过以下方法:
第一步,修改微端APP,定义要传递的参数gameParas,并通过base64加密。
public abstract class MicroBaseActivity extends Activity {
......
private void init() {
Log.i(TAG, "init: ");
// 注意:云游戏启动时带的参数必须经过base64编码,否则会抛出crash(IllegalArgumentException)
// gameParas为可选参数,不需要携带直接可以使用initConfig(String appVersion)进行初始化。
// "dGVzdCBkYXRhIGZvciBjbG91ZCBnYW1l"为测试用的gameParas,客户可以传自己需要的。
MicroContext.getInstance().initConfig(MicroUtils.getVersionName(this),
"dGVzdCBkYXRhIGZvciBjbG91ZCBnYW1l");
......
}
}
第二步,由于云端APP会提前预加载,微端在连接云游戏的时候云端游戏已经处于启动的状态了,所以无法之前传递启动参数来启动云端APP。
因此,需要修改云端APP,在云端APP中新增一个空的Activity作为云端APP的MAIN Activity,
并且在该Activity中新增广播监听,监听微端传递过来的gameParas,然后将gameParas作为intent参数启动游戏之前的主Activity。
public class MainActivity extends AppCompatActivity {
public static class CloudGamingReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
Log.i("CloudGamingReceiver", "GameParas:" + intent.getStringExtra("GameParas"));
// 收到需要的参数后再启动游戏的第一个activity
}
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction("android.intent.action.CLOUD_GAMING_STARTED");
registerReceiver(new CloudGamingReceiver(), intentFilter);
}
}
微端包在热更新完成后,有可能会遇到游戏包里的个别so访问资源找不到的问题,原因是该游戏so通过未知方式获取到base.apk的文件路径并访问其中资源,而预期是访问补丁包apk里的资源。这种情况可以将该游戏so的文件名添加到工程配置项里解决,见 /assets/microSettings.xml 的配置项 update_so_list 。
如果您不确定哪些so存在这种问题,可以进行如下测试。
第一步,将microSettings.xml里的debug项值改为true,并将游戏apk中lib下的所有可疑so文件名都填写到update_so_list字段的value值中(用英文逗号分隔)。例如
<settings>
......
<setting key="debug" value="true" />
<setting key="update_so_list" value="libunity.so,libxxx1.so,libxxx2.so" />
</settings>
第二步,编译生成微端包并运行到手机,执行热更新流程。
第三步,热更新完成点击重启,同时log中过滤“redirect so”字段,查看过滤的结果中包含了哪些so,将这些so保留,其他so从update_so_list 中移除,并把debug字段改为false,重新生成微端包并验证热更新流程。
第四步,构建生成微端apk,并校验微端apk生成是否正常。
补丁包在下载过程中会根据云游戏的状态来自动调节下载速度,默认是三档(256、512、1024)。
如果想要根据需求自定义修改,请按照以下步骤,
1、打开工程assets下的microSettings.xml,
<?xml version="1.0" encoding="utf-8"?>
<settings>
<!--设置三档下载速度,微端会根据当前云游戏状态进行调节,默认是(256、512、1024)-->
<setting key="download_speed_low" value="512" />
<setting key="download_speed_middle" value="1024" />
<setting key="download_speed_high" value="2048" />
</settings>
1、打开micro-ui/src/main/java/com/tencent/tcr/micro/MicroBaseActivity.java
private void init() {
......
// 本地补丁包存在时加载本地补丁包,不存在则直接开始下载
if (MicroConstant.HOT_UPDATE && FileUtils.fileIsExists(MicroConstant.LOCAL_DEBUG_PATCH)) {
showFilePickUpDialog();
} else {
// 当前下载时机处于Activity启动阶段,客户可以根据自己需要选择合适时机下载
MicroHotUpdateBiz.getInstance().startDownload();
}
}
将MicroHotUpdateBiz.getInstance().startDownload()放到您需要开始下载的地方。
1、打开工程assets下的microSettings.xml,
<?xml version="1.0" encoding="utf-8"?>
<settings>
...
<!-- 是否使用热更新的方式进行升级转化。 -->
<setting key="hot_update" value="false" />
<!-- 游戏包的地址。仅在hot_update为false的情况下才有意义。覆盖安装时使用。-->
<setting key="apk_url" value="https://cg-sdk-1258344699.file.myqcloud.com/test/test.apk" />
...
</settings>
2、打开micro-ui/src/main/AndroidManifest.xml,
<?xml version="1.0" encoding="utf-8"?>
<manifest package="com.tencent.tcr.micro.ui"
xmlns:android="http://schemas.android.com/apk/res/android">
<!-- 微端覆盖安装版本,需要新增安装权限和对应的provider-->
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" />
<application>
<provider
android:name="androidx.core.content.FileProvider"
android:authorities="${applicationId}.provider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/micro_filepaths" />
</provider>
</application>
</manifest>
在该文件中新增安装权限和对应的provider用于覆盖安装。
如果您的游戏apk使用了加固方案,那就需要在配置文件中设置对应参数,不同的加固厂商对应的flag值不同。微端目前已兼容了腾讯ACE加固和网易易顿加固方案。
对应配置文件 /assets/microSettings.xml 的update_flag字段。
值0表示没有使用加固或者使用了腾讯ACE加固,值12表示使用了爱加密加固,值17表示使用了网易易顿加固。例如
<settings>
<setting key="update_flag" value="17" />
</settings>
@Override
protected void onCreate(Bundle savedInstanceState) {
Log.i(TAG, "onCreate: ");
super.onCreate(savedInstanceState);
// 初始化bugly
// 应用启动后防止多次初始化bugly
if (!sBuglyInited) {
CrashReport.initCrashReport(getApplicationContext(), "xxxxx"/** AppId **/, true);
sBuglyInited = true;
}
}
我们为微端工程接入了bugly用于崩溃监测,如果您想要观测微端工程的crash情况,您可以申请自己的AppId.
申请地址https://bugly.qq.com/v2/index,
申请之后替换为您的AppId,打开bugly后台即可观测微端的崩溃数据。
<!-- 是否适配异形屏(摄像头区域)。 如果刘海屏适配遮挡了游戏的内容,可以关闭此开关-->
<setting key="support_display_cutouts" value="true" />
是否为微端应用进行异形屏配置,默认打开,如果打开后影响游戏显示,将此开关设为false。
为了保证多个版本的微端包的兼容问题,使用 tinker id 来保证微端包和补丁包的对应关系。
1、打开app/micro-update-support.gradle 文件,将文件中的tinkerId自动填写上自定义字符串,可以是 git 版本号或者 app 版本号。
2、打开hotUpdate/tools/tinker_config.xml,将文件中的TINKER_ID字段配置为tinker_id_加上上一步自定义的字符串。
<!-- 客户端空闲时间(可选)。 -->
<setting key="idle_threshold" value="60000" />
当客户端经过idle_threshold时间没有操作,会触发回调给到com.tencent.tcr.micro.sdk.biz.MicroCloudGameBiz.MicroCloudGameListener#onClientIdle接口, 您可以在该接口中做相关操作。该阈值默认为60000ms(1分钟),可以根据需要进行配置。
云游戏启动时,云端会设置一个固定码率上限。客户端会设置三个档位,分别对应标清,超清,原画,这三个档位的码率可以在/assets/microSettings.xml文件中新增配置,
<!-- 标清 -->
<setting key="bitrate_upper_limit_low" value="2000" />
<!-- 超清 -->
<setting key="bitrate_upper_limit_middle" value="5000" />
<!-- 原画 -->
<setting key="bitrate_upper_limit_high" value="8000" />
如果您要对微端APK进行重打包操作,需要保证AndroidManifest.xml文件里的资源ID在重打包前后不会发生改变。否则在热更新后(在补丁包里)会找不到对应的资源。
微端包需要将游戏包中lib下的libmain.so拷贝到微端工程的libs,并打入到微端apk中。
请使用oaid的1.1.0或以上的版本,否则热更新后oaid会出现以下crash。
java.lang.NullPointerException: Attempt to invoke virtual method 'int java.lang.Integer.intValue()' on a null object reference
at com.bun.miitmdid.core.MdidSdkHelper.InitSdk()
如果热更新后发现运行崩溃,并出现以下堆栈,这个是因为游戏apk中的apache仓库是stub,插件化场景下无法正常运行。
Caused by: java.lang.RuntimeException: Stub!
at org.apache.http.****
请在生成补丁包时使用以下命令去除游戏apk中的apache仓库。
./generate_patch.sh 游戏APK路径 true
由于sdk内部在api小于19时使用到了存储权限,所以对存储权限加了android:maxSdkVersion="18"的限制。会导致app在申请存储权限的时候会被这个限制覆盖掉,无法正常弹出权限申请框。
解决方法:申请android.permission.WRITE_EXTERNAL_STORAGE时加上tools:node="replace"。
<use-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE tools:node="replace"">