Shiply Android 应用内升级SDK接入指引
一、隐私安全说明
Shiply灰度升级SDK
版本:2.2.0
更新时间:2024年7月19日
SDK介绍:为移动开发者提供专业的灰度发布能力,帮助开发者快速验证实验版本。
服务提供方:深圳市腾讯计算机系统有限公司
接入指引:Shiply灰度升级SDK接入指引
隐私保护规则:《Shiply灰度升级SDK隐私保护规则》
二、接入SDK
在项目根目录gradle文件引入仓库:
allprojects {
repositories {
maven { url "https://tencent-tds-maven.pkg.coding.net/repository/shiply/repo" }
}
}
在需要接入灰度的包的gradle文件添加依赖:
dependencies {
implementation("com.tencent.shiply:upgrade:2.2.0")
implementation("com.tencent.shiply:upgrade-ui:2.2.0") // 弹框ui相关,业务方如果自己自定义弹框,可以不依赖这个库
}
三、初始化SDK
3.1 最简初始化
UpgradeConfig.Builder builder = new Builder();
UpgradeConfig config = builder.appId("xxxxxxx").appKey("xxxxx-xxxx-xxxx-xxxx-xxxxxxxxxx").build();
UpgradeManager.getInstance().init(getApplication(), config);
3.2 其他可选设置
Map<String, String> map = new HashMap<>();
map.put("UserGender", "Male");
UpgradeConfig.Builder builder = new Builder();
builder.systemVersion(String.valueOf(Build.VERSION.SDK_INT)) // 用户手机系统版本,用于匹配shiply前端创建任务时设置的系统版本下发条件
.customParams(map) // 自定义属性键值对,用于匹配shiply前端创建任务时设置的自定义下发条件
.cacheExpireTime(1000 * 60 * 60 * 6) // 灰度策略的缓存时长(ms),如果不设置,默认缓存时长为1天
.internalInitMMKVForRDelivery(true) // 是否由sdk内部初始化mmkv(调用MMKV.initialize()),业务方如果已经初始化过mmkv可以设置为false
.userId("xxx") // 用户Id,用于匹配shiply前端创建的任务中的体验名单以及下发条件中的用户号码包
.customLogger(logger); // 日志实现接口,建议对接到业务方的日志接口,方便排查问题
可以参考GitHub Demo: https://github.com/BuglyDevTeam/BuglyBetaUploader
四、检查更新
通过调用 UpgradeManager
的 checkUpgrade
方法触发检查更新
检查更新主要有APP首次启动时自动检查更新、用户主动点击「检测升级」按钮两种场景。
4.1 场景一:APP首次启动时自动检查更新
UpgradeManager.getInstance().checkUpgrade(false, null, new DefaultUpgradeStrategyRequestCallback());
DefaultUpgradeStrategyRequestCallback是SDK提供的默认更新策略回调接口实现类:
- 收到的更新策略提醒类型如果是红点,不会触发升级弹框;
- 收到的更新策略提醒类型如果是弹框提醒或者是全部(包括红点和升级弹框),会触发升级提示弹框,这里的升级弹框有限频逻辑,会遵循前端页面的配置(总弹窗次数和弹窗间隔);
4.2 场景二:用户主动点击「检测升级」按钮检查更新
UpgradeManager.getInstance().checkUpgrade(true, null, new UpgradeReqCallbackForUserManualCheck());
UpgradeReqCallbackForUserManualCheck是SDK提供的另一个更新策略回调接口实现类:
- 收到的更新策略提醒类型不管是红点、弹框或者是全部(包括红点和升级弹框),都会触发升级提示弹框;
- 这里的升级弹框不会有限频逻辑;
五、差量APK支持
SDK支持差量APK下载与合成能力,可以帮助业务方节省CDN流量。业务可按以下方式接入:
5.1 添加差量包依赖
dependencies {
implementation("com.tencent.shiply:upgrade-diff-pkg-patch:2.2.0") // 用于差量APK合并,如果业务方不使用差量能力,可以不依赖这个包
}
5.2 初始化差量包Handler和差量包的基准包来源
UpgradeConfig.Builder builder = new Builder();
// 差量APK处理器,负责差量包下载与合成
builder.diffPkgHandler(new DiffPkgHandler());
// 差量包基准包文件获取方式,以下二选一
builder.basePkgFileForDiffUpgrade(new OriginBasePkgFile()); // 表示基于原始文件生成差量包,不支持渠道包差量
builder.basePkgFileForDiffUpgrade(new ZipDataBasePkgFile()); // 表示基于渠道包文件的纯数据区域生成差量包,支持渠道包差量,业务方的渠道号是写在V2签名区域时请使用这种方式
UpgradeConfig config = builder.build();
UpgradeManager.getInstance().init(getApplication(), config);
六、自定义UI弹窗
- 业务方可以实现自定义的UpgradeStrategyRequestCallback,并且在checkUpgrade时传入自定义实现类;
- 在UpgradeStrategyRequestCallback#onReceiveStrategy(UpgradeStrategy strategy)方法中触发自定义UI弹窗;
- 在业务自己实现的弹窗中,如果用户选择更新下载,业务方可以通过调用UpgradeManager.getInstance().startDownload()来触发下载逻辑,下载完成后,会自动弹出安装界面;
手动触发下载
// 执行下载,调用UpgradeConfig中定义的downloader
UpgradeManager.getInstance().startDownload();
// 执行下载,userDefault: 是否强制使用SDK默认下载器下载
UpgradeManager.getInstance().startDownload(boolean userDefault);
注意:如果业务方自定义UI弹框,业务方需要自己处理前端页面配置的弹框总次数和弹框间隔逻辑
七、自定义下载器
SDK内置了下载能力,如果希望使用业务自己的下载器,可以通过实现IDownloader实现具体逻辑
public interface IDownloader {
void download(String url, long targetSize, String apkFullName,String apkMd5, DownloadListener listener);
void stop();
}
实现IDownloader接口后,在SDK初始化时,UpgradeConfig.downloader 设置为自定义Downloader
UpgradeConfig.Builder builder = new Builder();
// 业务方自己实现的Downloader
builder.customDownloader(new MyDownloader());
SDK内部注册的FileProvider配置的访问目录如下:
<?xml version="1.0" encoding="utf-8"?>
<paths>
<external-files-path
name="my_download"
path="Download"/>
</paths>
如果业务方自定义下载目录不是external-files-path的Download目录,需要在业务方工程的res/xml目录下面增加new_app_file_paths.xml文件,在文件中配置业务方自己的下载路径
<?xml version="1.0" encoding="utf-8"?>
<paths>
<external-path
name="UpgradeAPK"
path="DownloadDir"/>
</paths>
上面
具体可以参考:https://developer.android.com/reference/androidx/core/content/FileProvider
八、自定义安装器
SDK内部实现了APK安装逻辑,业务方如果希望在真正安装APK之前做一些额外逻辑,例如渠道包回写等,可以通过实现Installer接口来增加自定义处理逻辑
public interface Installer {
/**
* 安装结果回调接口
*/
interface InstallCallback {
/**
* 安装结果回调
* @param isSuccess 是否成功唤起系统安装器
*/
void onGetInstallResult(boolean isSuccess);
}
/**
* 安装APK
* @param apkPath apk 包路径
* @param apkMd5 apk md5
* @param callback 安装结果回调
*/
void installApk(String apkPath, String apkMd5, InstallCallback callback);
}
实现Installer接口后,在SDK初始化时,将UpgradeConfig.customInstaller 设置为自定义Installer
UpgradeConfig.Builder builder = new Builder();
// 业务方自己实现的Installer
builder.customInstaller(new MyInstaller());
九、 静默下载接口
业务方如果想实现静默下载能力,可以在拉取到后台的灰度升级策略后调用UpgradeManager.getInstance().startDownloadWithoutInstall接口
/**
* 启动下载,下载完成后不触发安装,用于业务方静默下载场景或者自定义UI弹框展示自定义进度条场景
* @param resultListener 更新策略处理结果回调,当差量包下载合并完成或者全量包下载完成后会将完整APK路径回调通知给业务方
*/
public void startDownloadWithoutInstall(HandleResultListener resultListener) {
...
}
/**
* ApkBasicInfo处理监听接口,整个处理包括准备基准文件、下载差量文件、合成完整文件、下载完整文件、安装5个阶段
* 当ApkBasicInfo中没有差量包信息时,只会执行下载完整文件、安装两个阶段;
* 当ApkBasicInfo中有差量包信息时,会先准备基准文件,接着下载差量、合成完整文件,这三步任何一步失败都会下载完整文件兜底;
*/
public interface HandleResultListener {
/**
* 获取到了完整的新版本APK文件的路径
* @param info
* @param fullApkPath 新版本APK文件的路径,可能是从差量包合成得到,也可能是下载的全量包
*/
void onGetFullApkPath(ApkBasicInfo info, String fullApkPath);
/**
* 获取新版本APK文件的路径失败,差量合成失败并且全量下载也失败时才会触发
*/
void onGetFullApkPathFailed();
/**
* 开始生成基准包
*/
void onPrepareBaseFileStart();
/**
* 基准包生成结束
* @param isSuccess
* @param errCode
* @param errString
*/
void onPrepareBaseFileEnd(boolean isSuccess, int errCode, String errString);
/**
* 开始下载差量包
*/
void onDownloadDiffFileStart();
/**
* 差量包下载进度更新
* @param percent
*/
void onUpdateDiffFileDownloadPercent(float percent);
/**
* 差量并下载结束
* @param isSuccess
* @param errCode
* @param errString
*/
void onDownloadDiffFileEnd(boolean isSuccess, int errCode, String errString);
/**
* 开始合成新版本完整包
*/
void onPatchStart();
/**
* 新版本完整包合成结束
* @param isSuccess
* @param errCode
* @param errString
*/
void onPatchEnd(boolean isSuccess, int errCode, String errString);
/**
* 开始下载新版本完整包
*/
void onDownloadFullFileStart();
/**
* 新版本完整包下载进度更新
* @param percent
*/
void onUpdateFullFileDownloadPercent(float percent);
/**
* 新版本完整包下载结束
* @param isSuccess
* @param errCode
* @param errString
*/
void onDownloadFullFileEnd(boolean isSuccess, int errCode, String errString);
}
业务方需要实现HandleResultListener,在收到onGetFullApkPath回调后缓存info参数和fullApkPath参数,
然后在特定时机将这两个参数传给UpgradeManager.getInstance().startInstall(ApkBasicInfo info, String fullApkPath)接口,以触发安装逻辑。
注意:HandleResultListener各回调接口中的errString参数都可能为空,业务方如果先在java代码中接入,后续如果转换成kotlin代码,务必要将errString类型改成String?, 否则会出现空指针问题;
十、 获取灰度策略配置信息
方式一:通过UpgradeManager.getInstance().checkUpgrade(true,null,UpgradeStrategyRequestCallback)强制发起网络请求
该方式会触发UpgradeStrategyRequestCallback#onReceiveStrategy(UpgradeStrategy strategy)回调,回调接口的UpgradeStrategy参数就是灰度策略数据
方式二:通过UpgradeManager.getInstance().getStrategy() 来获取灰度策略信息
该方式是取得本地缓存的灰度策略信息
public class UpgradeStrategy implements Serializable {
/**
* 弹窗 = 1,红点 = 2,ALL = 3
*/
private int remindType;
/**
* 该策略共弹框n次
*/
private int popTimes;
/**
* 该策略弹框最小时间间隔
*/
private long popInterval;
/**
* 安装包信息
*/
private ApkBasicInfo apkBasicInfo;
/**
* 弹窗相关信息
*/
private ClientInfo clientInfo;
/**
* 业务自定义参数
*/
private Map<String, String> extra;
}
安装包信息:
public class ApkBasicInfo implements Serializable {
/**
* 安装包名
*/
private String packageName;
/**
* md5
*/
private String apkMd5;
/**
* version code
*/
private int versionCode;
/**
* version name
*/
private String versionName;
/**
* build No
*/
private int buildNo;
/**
* 下载链接
*/
private String downloadUrl;
/**
* 安装包大小
*/
private long apkSize;
}
弹窗相关信息:
public class ClientInfo implements Serializable {
/**
* 弹窗标题
*/
private String title;
/**
* 弹窗描述信息
*/
private String description;
}
- 获取下发的额外扩展参数
- 业务在下发任务时可以在发布平台配置一些自定义的key-value键值对随灰度包一起下发,
- 这些信息会保存到UpgradeStrategy的extra字段中,业务可以自行获取这些键值对,做特殊处理。