前言

 近日, Google I/O 2019 上谷歌宣布推出一款新API,允许应用程序在用户使用时安装更新升级应用。该API名为“应用内更新API(In-app Updates API)”,能够使应用程序可以更好地通过Google Play控制检查和安装更新的方式。

 应用内更新支持即时更新和弹性更新两种方式。
 应用内更新仅适用于运行安卓 Android 5.0(API级别21)或更高版本的设备,并且要求您使用Play Core 1.5.0或更高版本。
 谷歌官方文档[英文版]:developer.android.com/guide/app-b…

 注意:由于是通过GP更新,对于国内产品可能不适用。因此本文应该是对开发国际App的童鞋有所帮助。

关键词

IMMEDIATE -- 即时更新
FLEXIBLE -- 弹性更新(灵活更新)
GP -- Google Play (Play Store)
AS -- Andriod Studio

即时更新

 请注意即时更新并非强制更新,只是全屏用户体验。虽然谷歌官方说要求用户更新并重新启动应用程序才能继续使用该应用程序,但是实际上用户也是可以取消更新的。当然谷歌提供了用户取消事件通知,你可以在用户取消时重新弹出要求更新界面,那么也就可以实现强制更新效果(下载过程中的取消不适用)。
 下图是谷歌提供的即时更新UI界面:

 即时更新,弹出更新提醒框后,用户依然可以取消更新,下载过程中也可以取消下载,系统将通过onActivityResult返回用户已取消状态码。但是一旦取消下载后,无法再次发起即时更新(系统总是返回用户已取消)。卸载重新安装后,可以清除该状态。
 用手机系统返回键取消的,不计入用户取消状态。
 下载完毕后,自动开始安装,安装可能会失败,失败后不会有onActivityResult通知,可以重新进入强制更新逻辑。
 安装过程中反复前后台切换的话,可能会通过onActivityResult收到安装成功提醒,但是结果并不一定是成功的。
 一旦进入安装过程,也就无法取消了。

弹性更新(灵活更新)

 弹性更新,将弹出一个浮动窗口,让用户确认开始更新。用户同意更新后,进入后台下载,用户可以继续使用App。但下载完毕后,安装过程只能在前台进行。为不打扰用户,下载完毕后,不弹框提醒,谷歌推荐在onResume时,检测到如果下载完成,则启动安装过程。安装时机是可控的,但不需要用户确认。

 开始弹性更新前,用户可以取消更新。取消之后,不会记录用户取消状态,可再次发起弹性更新。
 后台下载的时候,技术上还可以将下载进度界面弹出来,变为即时更新,当然这个并不必要(甚至可以算作是一个BUG),所以这种变更后的下载完毕后是否自动安装,笔者并没有研究。实在有兴趣的童鞋可以研究一下。
 可以监听下载进度,然后自行处理UI,当然并没有这个必要。

 无论哪种更新方式,谷歌都提供更新确认UI,下载进度UI,以及安装过程UI,无需App再自行编写UI。参考官方文档。 安装完毕后会通过onActivityResult返回更新成功或失败。

实战

 官网文档里面的代码是无法通过编译的,编译解决后也可能直接崩溃,另外笔者在研究过程中也踩坑不少,花了较多的时间才能将流程跑通,因此有必要将研究过程记录下来。
 因为是走线上GP更新,要想编码调试应用内更新,首先你得有一个GP账号,然后上架一个产品,推荐新建一个Demo产品来测试。
 大致步骤如下:

  • 科学上网,首先你的环境需要能够访问GP。
  • 使用Android Studio 新建一个Demo工程。
  • 在build.gradle里面,dependencies中添加GP库:
    implementation 'com.google.android.play:core:1.5.0'
复制代码
版本号必须为1.5.0或以上。
复制代码
  • 然后在MainActivity.onCreate方法中添加如下代码:
final int REQUEST_CODE_UPDATE = 9001;AppUpdateManager appUpdateManager = AppUpdateManagerFactory.create(this);
m_appUpdateManager = appUpdateManager;
Task<AppUpdateInfo> appUpdateInfo = appUpdateManager.getAppUpdateInfo();
appUpdateInfo.addOnCompleteListener(new OnCompleteListener() {@Overridepublic void onComplete(Task task) {if (task.isSuccessful()) {// 监听成功,不一定检测到更新AppUpdateInfo it = (AppUpdateInfo)task.getResult();    if (it.updateAvailability() == UpdateAvailability.UPDATE_AVAILABLE&& it.isUpdateTypeAllowed(IMMEDIATE)) { // 检测到更新可用且支持即时更新 try {// 启动即时更新appUpdateManager.startUpdateFlowForResult(it, IMMEDIATE, MainActivity. this, REQUEST_CODE_UPDATE);} catch (Exception e) {e.printStackTrace();}}} else {// 监听失败}}
});
复制代码

 如果startUpdateFlowForResult返回true,那么你将看见即时更新确认界面,点击Update即可开始下载更新。不过不着急,准备工作还没做好呢,接着往下看:

  • 在build.gradle中,将版本号修改一下
        versionCode 1000versionName "2.0.1000"
复制代码

 随便改成多少都行,总之要稍微大一点的数字,主要是versionCode,GP升级主要是检查versionCode来的。

  • 使用Build / Generate Signed Bundle / APK... 创建一个签名文件,再打包一个Release APK安装包。
  • 将安装包提交到GP发布。
  • 修改build.gradle中的版本号,将versionCode改为100,总之就是改小就行。
  • 直接编译到设备运行,此时肯定是检测不到更新的。
  • 打开GP,直到刷到Demo App 最新版本信息,可以使用包名搜索。包名在build.gradle中applicationId即包名,可以自行修改,但必须要跟GP版本一致。
  • 直到刷到Demo App 最新版本信息后,还需要GP上显示“Update”按钮才表示可以更新。
  • 直到GP 显示可以更新后,回到AS 重新调试Demo,应该能够检测到更新信息了
  • 如果你用Debug环境来调试,那么必须将release版的签名信息也应用到Debug,打开工程设置,创建一个签名信息: 然后将config应用到Debug:

这样调试环境便具备了和Release包相同的签名信息。
 如图所示,不出意外的话,已经检测到线上versionCode为1000,updateAvailability为2(UpdateAvailability.UPDATE_AVAILABLE)表示更新可用,另外两个检测为true表示当前可以进行即时更新和弹性更新。startUpdateFlowForResult就可以弹出更新确认界面了,接下来应该在MainActivity.onActivityResult中检测返回值:

    @Overridepublic void onActivityResult(int requestCode, int resultCode, Intent data) {if (requestCode == REQUEST_CODE_UPDATE) {if (resultCode == Activity.RESULT_OK) {Log.w("GPUpdate", "应用内更新成功");} else if (resultCode == Activity.RESULT_CANCELED) {Log.w("GPUpdate", "应用内更新, 用户取消");} else {Log.w("GPUpdate", "应用内更新,遇到错误");}}}
复制代码

 如果要使用弹性更新,下载任务放在后台进行,那么startUpdateFlowForResult应该指定AppUpdateType.FLEXIBLE参数,依然需要用户确定更新,然后更新UI隐藏,用户可以继续操作App。

 可以在MainActivity.onResume中添加下载后相关处理代码,

    @Overrideprotected void onResume() {super.onResume();Task<AppUpdateInfo> appUpdateInfo = m_appUpdateManager.getAppUpdateInfo();appUpdateInfo.addOnSuccessListener(new OnSuccessListener() {@Overridepublic void onSuccess(Object o) {AppUpdateInfo it = (AppUpdateInfo)o;traceAppUpdateInfo(it);try {if (it.installStatus() == InstallStatus.DOWNLOADED) {// 只有后台下载才会有这个通知Log.w("GPUpdate", "下载完毕,开始执行安装");m_appUpdateManager.startUpdateFlowForResult(it, IMMEDIATE, MainActivity. this, REQUEST_CODE_UPDATE);}} catch (Exception e) {e.printStackTrace();}}});}
复制代码

 这样可以在下载完成后,用户切换应用重新进入App时可以启动安装过程,注意这里只能使用AppUpdateType.IMMEDIATE参数,因为安装过程不能在后台进行,也不提供用户选择的入口,调用成功即开始安装,安装过程是不能取消的。
 技术上也可以监听后台下载进度,下载完毕后立即启动安装,但是这样会打断用户操作,体验非常不友好,因此并不推荐。

重要:按上述步骤,可以调试下载更新过程,但最终升级会是失败的,原因可能是签名证书问题。若要升级真正能成功,那么还需要以下步骤。

  1. 修改versionCode = 1004, versionName = "2.0.1004"
  2. 打Release安装包
  3. 提交GP发布,发布时将更新信息填入版本号2.0.1004
  4. GP刷到最新版本信息
  5. 使用GP下载2.0.1008版进行安装
  6. 再修改versionCode = 1008, versionName = "2.0.1008"
  7. 打Release安装包
  8. 提交GP发布,发布时将更新信息填入版本号2.0.1008
  9. GP刷到最新版本信息,而且需要显示“更新”按钮,千万不要更新
  10. 找到刚才安装好的2.0.1004,重新启动
  11. 此时应该可以弹出更新确认界面了,点击“更新”。
  12. 等待安装完毕,GP会重新启动Demo App,查看版本号,应该变为2.0.1008了,更新成功,恭喜!大功告成!

PS:为了快速查看版本更新是否成功,建议在Demo界面上放一个TextView,显示版本号。

注意事项

  • 你的手机上,你的GP账号应该要至少下载过一次App。
  • 如果总是刷不到最新版本信息,那么Kill 掉GP,重新启动试试,确保GP缓存失效。
  • 调试用的版本号一定要低于GP线上版本号,主要是VersionCode。
  • 本地包可以调试下载更新过程,但是最终会更新失败,如果从GP下载签名再打入本地包,也许能解决这个问题,有兴趣的童鞋可继续深入研究。
  • GP刷出新版本,通常需要几个小时的时间,30分钟算是很快的了,而且就算刷到最新版本信息,还不一定能进行更新(这可能是GP的BUG)。为了能快速刷出新版本信息,可以在GP后台发布内测版本,添加测试用GP账号到白名单。内测版本发布后,白名单内测用户在几秒钟可以刷到最新信息。

添加白名单后,记得一定要将邀请链接发给对方,确认加入后,才能正式成为内测用户。

转载于:https://juejin.im/post/5cd571885188252e6b3d55af

Android 应用内更新 Support in-app updates [GP官方支持]相关推荐

  1. Android 6.0 7.0 8.0 一个简单的app内更新版本-okgo app版本更新

    登陆时splash初始页调用接口检查app版本.如有更新,使用okGo的文件下载,保存到指定位置,调用Android安装apk. <!-- Android 8.0 (Android O)为了针对 ...

  2. android更新完之后怎么打开app,在Android中启动/更新后,检查App是否第一次打开

    我想在每次第一次更新或安装应用程序后打开我的应用程序时运行服务.如何在启动后检查App是否首次打开? 我试过这个但是onCreate方法中的代码,但我在更新我的代码时得到isFirst = true, ...

  3. Android 增量更新实例(Smart App Updates)

    http://892848153.iteye.com/blog/2022851 转自:http://my.oschina.net/liucundong/blog/160436 目录[-] 官方说明 实 ...

  4. Android N 应用内更新

    2017-03-28 文章目录 检测到需要升级时 `new ApkDownLoad().execute()`就可以了,其中`UpdateUtils.getLong()`是一个`SharedPrefer ...

  5. 96.android 简单的更新APP、下载安装APK(四种方式)

    //第一种 下载更新使用OKHttp+ProgressDialog进度条+第三方AlertDialog //第一步 在Manifest.xml里面写权限: <!-- 网络权限--> < ...

  6. 【Google Play】App Bundle 使用详解 ( 简介 | 应用内更新 | 即时更新 | 灵活更新 )

    Google Play 上架完整流程 系列文章目录 [Google Play]创建 Google 开发者账号 ( 注册邮箱账号 | 创建开发者账号 ) [Google Play]创建并设置应用 ( 访 ...

  7. Android studio 实验过程中遇到的问题之android.support.v7.app.AppCompatActivity不能使用的解决办法

    android.support.v7.app.AppCompatActivity不能使用的解决办法 在构建项目时使用 android.support.v7.XX android.support.v4. ...

  8. 【开源项目】Android开发内置App自动升级

    1.准备工作,首先需要在AndroidManifest.xml中的application中加入以下内容 <providerandroid:name="android.support.v ...

  9. 解决Android v4、v7包导入标红问题import android.support.v4.app.ActivityCompat;import android.support.v7.app

    解决Android v4.v7包导入标红问题 由于安卓经常性的升级,很多包都有过迁移,会造成有些包的路径变了. 如果有如下错误: import android.support.v4.app.Activ ...

最新文章

  1. 【案例】常驻查询引发的thread pool 性能问题之二
  2. 【转】使用ant来调用Jmeter,并定制运行时参数
  3. Mysql 查询返回结果空时间错误
  4. microsoft office 2007 完全 卸载 工具 来自微软官方
  5. ARM体系的异常中断
  6. python http服务器_Python简单http服务实现
  7. 计算机电源烧保险,ATX电脑电源保险换了就烧怎么维修?
  8. Spring学习Ioc
  9. python画正态分布_用python的matplotlib画标准正态曲线
  10. 爱在心中【tarjan + 缩点】
  11. Minecraft mod制作简易教程(一)——配置工作环境
  12. Python 小白学习之:linux 基础和 python 入门
  13. 基于Webmagic的爬取B站用户数据的爬虫
  14. python怎么接单子平台有哪些_17个Python接私活的平台,总有适合你的,有技术就有收入...
  15. Linux DRM(二)基本概念和特性
  16. 你猜,帕特∙基辛格、郭尊华、郭为、田溯宁为什么相视而笑?
  17. bing的搜索框按回车是换行而不是搜索
  18. python assign
  19. 【vue warning】avoid mutating a prop directly
  20. 数字电视技术英文专业词汇释义

热门文章

  1. wordpress插件-Media folder插件汉化版_优化加速插件
  2. python 字典操作 内存占用_关于 python 的 dict 的内存占用问题....
  3. 基于Spring+SpringMVC+Mybatis架构的开源博客
  4. WordPress主题LensNews模板源码,2.2版本多功能新闻积分商城主题
  5. 百度SEO站群自采集壁纸源码小韩美化版
  6. 帝国CMS7.5仿《问答库》题库问答学习平台网站源码 带手机版
  7. php修罗XiunoBBS轻论坛程序源码开源版
  8. Rclone for Android – 云服务/网盘文件管理工具 Rclone 的 Android 客户端
  9. Linux安装mongodb数据库最新版(全网最细)
  10. 利用对象池优化数据库操作