本文介绍云发布服务Android端接入SDK的详细操作。
在接入阿里云移动SDK之前,请明确您已在阿里云移动研发平台 ( EMAS ) 上建立相关产品,并获得对应的appkey和appSecret。
为避免在日志中泄漏参数
appkey
/appsecret
或App运行过程中产生的数据,建议线上版本关闭SDK调试日志。由于所有用户使用统一的SDK接入,在接入过程中需要在代码中设置
appkey
/appsecret
参数,而此类参数与计量计费密切相关,为防止恶意反编译获取参数造成信息泄漏,建议您开启混淆,并进行App加固后再发布上线。
一、Android SDK接入
1、添加依赖:Maven仓库依赖接入
在项目build.gradle中添加阿里云Maven仓库地址:
repositories {
maven { url "http://maven.aliyun.com/nexus/content/repositories/releases" }
}
app模块的build.gradle的dependencies节点内添加:
implementation 'com.taobao.android:update-main:1.2.0-open'
2、接入服务
在自定义Application类的onCreate里面启动服务:
private void initUpdate() {
//以下引号部分需要客户根据自己的应用进行配置()
Config config = new Config();
//填写appkey
config.group = appkey + "@android";
//渠道号,非多渠道打包时可以不填。
config.ttid = ttid;
config.isOutApk = false;
//app name
config.appName = appName;
//设置自定义弹窗
setCustomDialog(this, true);
//初始化
UpdateRuntime.init(this, config.ttid, config.appName, config.group);
UpdateDataSource.getInstance().init(this, config.group, config.ttid, config.isOutApk,
appkey, appsecret, ttid, new UpdateAdapter());
//设置是否开启缓存,true开启,false关闭
UpdateDataSource.getInstance().setEnableCache(true);
//设置缓存有效时间,单位ms,eg: 缓存有效时间12h
UpdateDataSource.getInstance().setCacheValidTime(12 * 60 * 60 * 1000);
//true:同步, false:异步
UpdateDataSource.getInstance().startUpdate(false);
}
/* 设置自定义弹窗
* @param context Context
* @param customDialog 是否自定义弹窗
*/
private void setCustomDialog(final Context context, boolean customDialog) {
ApkUpdater apkUpdate = new ApkUpdater(context);
apkUpdate.setUpdateLog(new IUpdateLog() {
@Override
public void d(String s) {
}
@Override
public void d(String s, Throwable throwable) {
}
@Override
public void e(String s) {
}
@Override
public void e(String s, Throwable throwable) {
}
@Override
public void i(String s) {
}
@Override
public void i(String s, Throwable throwable) {
}
@Override
public void w(String s) {
}
@Override
public void w(String s, Throwable throwable) {
}
@Override
public void v(String s) {
}
@Override
public void v(String s, Throwable throwable) {
}
});
//设置apk下载进度回调
apkUpdate.setApkDownloadListener(new ApkDownloadListener() {
@Override
public void onPreDownload() {
//下载开始
}
@Override
public void onDownloadProgress(int progress) {
//下载进行中
}
@Override
public void onStartFileMd5Valid(String filePath, String fileSize) {
//开启文件md5校验
}
@Override
public void onFinishFileMd5Valid(boolean success) {
//完成文件校验
}
@Override
public void onDownloadFinish(String url, String filePath) {
//下载完成
}
@Override
public void onDownloadError(String url, int errorCode, String msg) {
//下载出错
}
});
if (customDialog) {
//自定义有更新信息时的Dialog
apkUpdate.setUpdateNotifyListener(new UpdateNotifyListener() {
@Override
public void onNotify(Activity activity, CustomUpdateInfo customUpdateInfo, final UserAction userAction) {
AlertDialog.Builder builder = new AlertDialog.Builder(activity);
builder.setTitle("新版本升级");
builder.setMessage(customUpdateInfo.getInfo() + "\n版本:" + customUpdateInfo.getVersion() + "\n安装包大小:" + customUpdateInfo.getSize() + "\n是否强制升级:" + customUpdateInfo.isForceUpdate());
builder.setCancelable(false);
builder.setPositiveButton(userAction.getConfirmText(), new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int i) {
userAction.onConfirm();
dialogInterface.dismiss();
}
});
builder.setNegativeButton(userAction.getCancelText(), new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int i) {
userAction.onCancel();
dialogInterface.dismiss();
}
});
builder.create().show();
}
});
//如果是强制更新,用户点击更新Dialog的取消按钮时会弹出这个Dialog;如果不是强制更新,则不会弹出这个Dialog
apkUpdate.setCancelUpdateNotifyListener(new UpdateNotifyListener() {
@Override
public void onNotify(Activity activity, CustomUpdateInfo customUpdateInfo, final UserAction userAction) {
AlertDialog.Builder builder = new AlertDialog.Builder(activity);
builder.setTitle("强制升级取消提示");
builder.setMessage(customUpdateInfo.getInfo());
builder.setCancelable(false);
builder.setPositiveButton(userAction.getConfirmText(), new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int i) {
userAction.onConfirm();
dialogInterface.dismiss();
}
});
builder.setNegativeButton(userAction.getCancelText(), new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int i) {
userAction.onCancel();
dialogInterface.dismiss();
}
});
builder.create().show();
}
});
//apk下载完成后,安装Dialog
apkUpdate.setInstallUpdateNotifyListener(new UpdateNotifyListener() {
@Override
public void onNotify(Activity activity, CustomUpdateInfo customUpdateInfo, final UserAction userAction) {
AlertDialog.Builder builder = new AlertDialog.Builder(activity);
builder.setTitle("个性化安装");
builder.setMessage(customUpdateInfo.getInfo());
builder.setCancelable(false);
builder.setPositiveButton(userAction.getConfirmText(), new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int i) {
userAction.onConfirm();
dialogInterface.dismiss();
}
});
builder.setNegativeButton(userAction.getCancelText(), new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int i) {
userAction.onCancel();
dialogInterface.dismiss();
}
});
builder.create().show();
}
});
//自定义更新结果提示
apkUpdate.setUpdateResultListener(new UpdateResultListener() {
@Override
public void onFinish(int i, int i1, String s) {
}
});
} else {
//接口设为null,则弹窗默认使用SDK内置的Dialog
apkUpdate.setUpdateNotifyListener(null);
apkUpdate.setCancelUpdateNotifyListener(null);
apkUpdate.setInstallUpdateNotifyListener(null);
}
}
AndroidManifest.xml里面指定自定义Application:
<application
android:name=".MyApplication"
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@style/AppTheme" >
</application>
AndroidManifest.xml里面Application标签内添加安装应用的权限,如示例:
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" />
AndroidManifest.xml里面Application标签内注册FileProvider,如示例:
<provider
android:name="com.taobao.update.provider.UpdateProvider"
android:authorities="${applicationId}.update.provider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/apk_paths" />
</provider>
在res
目录下,创建apk_paths.xml
文件,内容如下:
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<external-cache-path name="external_apk_update" path="apkupdate/" />
<cache-path name="apk_update" path="apkupdate/" />
<root-path name="root_apk_update" path ="storage/"/>
</paths>
3、接口说明
3.1 前后台查询更新
手动触发更新接口。 每次都会请求接口,不会使用缓存。
//参数指定同步/异步,true是同步,false是异步 UpdateDataSource.getInstance().startManualUpdate(false)
自动触发更新接口。如果开启了缓存且在缓存有效期内,则优先使用缓存。
//参数指定同步/异步,true是同步,false是异步 UpdateDataSource.getInstance().startUpdate(false)
3.2 缓存功能说明
如果是调用UpdateDataSource.getInstance().startManualUpdate()
方法,不会使用缓存。
开启缓存功能后,每次请求更新接口前会先检查本地是否有之前接口Response的缓存,如果有且在缓存有效时间内,则直接使用本地缓存的接口Response。
//设置是否开启缓存,true开启,false关闭
UpdateDataSource.getInstance().setEnableCache(true);
缓存有效时间可以自定义设置。
如果不设置缓存有效时间,或设置为小于0的数字且开启了缓存功能,默认缓存有效时间为24h。
//自定义设置缓存有效时间,单位ms
UpdateDataSource.getInstance().setCacheValidTime(12 * 60 * 60 * 1000);
开启缓存后,缓存时长不宜过长,过长可能会导致设备长时间无法接收到最新的更新/灰度指令。
3.3 自定义升级提示弹窗
apkUpdate.setUpdateNotifyListener(new UpdateNotifyListener() {
@Override
public void onNotify(Activity activity, CustomUpdateInfo customUpdateInfo, final UserAction userAction) {
AlertDialog.Builder builder = new AlertDialog.Builder(activity);
builder.setTitle("新版本升级");
builder.setMessage(customUpdateInfo.getInfo() + "\n版本:" + customUpdateInfo.getVersion() + "\n安装包大小:" + customUpdateInfo.getSize() + "\n是否强制升级:" + customUpdateInfo.isForceUpdate());
builder.setCancelable(false);
builder.setPositiveButton(userAction.getConfirmText(), new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int i) {
userAction.onConfirm();
dialogInterface.dismiss();
}
});
builder.setNegativeButton(userAction.getCancelText(), new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int i) {
userAction.onCancel();
dialogInterface.dismiss();
}
});
builder.create().show();
}
});
3.4 自定义取消强制升级的提示弹窗
apkUpdate.setCancelUpdateNotifyListener(new UpdateNotifyListener() {
@Override
public void onNotify(Activity activity, CustomUpdateInfo customUpdateInfo, final UserAction userAction) {
AlertDialog.Builder builder = new AlertDialog.Builder(activity);
builder.setTitle("强制升级取消提示");
builder.setMessage(customUpdateInfo.getInfo());
builder.setCancelable(false);
builder.setPositiveButton(userAction.getConfirmText(), new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int i) {
userAction.onConfirm();
dialogInterface.dismiss();
}
});
builder.setNegativeButton(userAction.getCancelText(), new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int i) {
userAction.onCancel();
dialogInterface.dismiss();
}
});
builder.create().show();
}
});
3.5 自定义下载完成后的安装提示弹窗
apkUpdate.setInstallUpdateNotifyListener(new UpdateNotifyListener() {
@Override
public void onNotify(Activity activity, CustomUpdateInfo customUpdateInfo, final UserAction userAction) {
AlertDialog.Builder builder = new AlertDialog.Builder(activity);
builder.setTitle("个性化安装");
builder.setMessage(customUpdateInfo.getInfo());
builder.setCancelable(false);
builder.setPositiveButton(userAction.getConfirmText(), new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int i) {
userAction.onConfirm();
dialogInterface.dismiss();
}
});
builder.setNegativeButton(userAction.getCancelText(), new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int i) {
userAction.onCancel();
dialogInterface.dismiss();
}
});
builder.create().show();
}
});
3.6 自定义更新结果提示
apkUpdate.setUpdateResultListener(new UpdateResultListener() {
@Override
public void onFinish(int mode, int errorCode, String errMsg) {
//不保证ui线程
}
});
3.7 自定义下载进度回调
apkUpdate.setApkDownloadListener(new ApkDownloadListener() {
@Override
public void onPreDownload() {
//下载开始
}
@Override
public void onDownloadProgress(int progress) {
//下载进行中
}
@Override
public void onStartFileMd5Valid(String filePath, String fileSize) {
//开启文件md5校验
}
@Override
public void onFinishFileMd5Valid(boolean success) {
//完成文件校验
}
@Override
public void onDownloadFinish(String url, String filePath) {
//下载完成
}
@Override
public void onDownloadError(String url, int errorCode, String msg) {
//下载出错
}
});
如果本次下载是从0开始且过程顺利,回调的调用路径为
onPreDownload() -> onDownloadProgress() -> onDownloadFinish()/onDownloadError()
,其余两个关于文件校验的方法并不会被调用。如果本次下载是断点续传,则下载完成后会进行文件完整性校验,会回调
onStartFileMd5Valid() -> onFinishFileMd5Valid()
。
3.8 自定义日志接口
apkupdate.setUpdateLog(new IUpdateLog() {
@Override
public void d(String msg) {
}
@Override
public void d(String msg, Throwable throwable) {
}
@Override
public void e(String smsg {
}
@Override
public void e(String msg, Throwable throwable) {
}
@Override
public void i(String msg) {
}
@Override
public void i(String msg, Throwable throwable) {
}
@Override
public void w(String msg {
}
@Override
public void w(String msg, Throwable throwable) {
}
@Override
public void v(String msg) {
}
@Override
public void v(String msg, Throwable throwable) {
}
});
二、混淆配置
如果开启了混淆,需要增加以下配置到您的混淆配置文件中:
#-------------------update-main------------------------------
-keepclassmembers class * {
@com.google.inject.Inject <init>(...);
}
# There's no way to keep all @Observes methods, so use the On*Event convention to identify event handlers
-keepclassmembers class * {
void *(**On*Event);
}
-keepclassmembers class ** {
public <init>(android.content.Context);
}
-keepclassmembernames class **.R$* {*;}
-keepclassmembernames class **.R {*;}
-keepclassmembers class **{
public static final <fields>;
}
-keep class com.taobao.update.apk.MainUpdateData{*;}
-keep class com.taobao.update.apk.ApkUpdater{*;}
#-------------------update-common------------------------------
-keep class com.taobao.update.common.framework.**{*;}
-keep class com.taobao.update.common.utils.**{*;}
-keep class com.taobao.update.common.dialog.**{*;}
-keep class com.taobao.update.common.Config{*;}
-keep class com.taobao.update.common.dialog.CustomUpdateInfo{
public <methods>;
}
-keep interface com.taobao.update.common.dialog.UpdateNotifyListener{*;}
三、测试验证
在您完成上述步骤之后,您可以通过EMAS控制台新建产品,构建发布并进行测试。