Google Play Core 里有两个功能,会悄悄决定你的商店页能不能自己变好:一个是应用内评价(In-App Review)API——用户不用离开应用就能打分和写评价;另一个是应用内更新(In-App Updates)——你可以请活跃用户直接更新到新版本,不必跳去 Play 商店。用得好,评分会稳步上升、卡在旧版本上的用户会明显减少;用得随意,则既打扰用户、又白白消耗一个你根本看不见的配额,最后拿到的不是数据而是一堆客服工单。

下面按真实动手顺序讲这两个 API:先看依赖前提,再谈请求时机与设计红线,然后是代码路径,最后是必须在真机上做的测试。全篇依据 Google 官方 Play Core 文档的行为,而贯穿始终的只有两条:你无法强制评价弹窗出现,你也无法承诺更新一定按你的时间表装上去——这两件事都由 Play 决定。你要做的是在对的时机、用对的更新类型去请求,并且在答案是「不行」的时候让应用照常运行。


1. 两个 API 各自做什么,以及它们故意不做什么

应用内评价流程会让你的应用弹出 Play 商店的评分卡片,用户可以给 1 至 5 星、可选写一段评论,提交后评论会送往 Play 商店并最终展示出来。但你拿不到关于自己这次请求的任何反馈:API 不会告诉用户是否评价了,甚至不会告诉你弹窗有没有显示。没有可以分支判断的返回值,没有星数可读,也没有办法按需再次弹出。

应用内更新则是提示活跃用户安装新版本。它不是遥控开关:安装从来不是静默的,重启从来不是强制的,更新也只向更高的 versionCode 前进。你能控制的是更新类型——灵活更新或立即更新——以及你通过发布时附带的更新优先级所表达的「推荐强度」。其余都由 Play 决定。

还有一个设计 UI 前就该知道的细节:如果应用处于封闭测试轨道,评价流程收集到的星级与评论会私下给到开发者,而不是公开发布。用来演练集成完全够用,但它和公开评分不是一回事。

2. 动手前必须核对的前提条件

由此得到两个实际结论。第一,如果你的应用依赖扩展文件,应用内更新这条路直接封死,只能通过商店页提示更新。第二,在没有 Play 商店的设备上,两个 API 都是「什么都不做」——它们会安静地失败。所以 UI 的门槛要建立在你自己那次请求调用的结果上,而不是假定功能可用。

3. 应用内评价:允许你开口的时机

Google 的规则很短也很硬。要在用户已经体验过足够多的内容、能给出有用反馈之后再触发:比如通关一关、导出一次成果、完成一次成功的会话。不要过度提示,每一次多余的提示都在消耗下面要讲的配额,也在消耗你本想讨好的人。

真正的硬性禁止在于「事先提问」。在呈现评分按钮或卡片之前和期间,应用不得向用户提问——既包括「你喜欢这个应用吗」这类意见问题,也包括「你会给它打 5 星吗」这类预测性问题。先用问题筛掉不满意的人,正是这条规则要防的事。如果你确实想做一个自己的入口,那就直接指向 Play 商店页面——一个始终可用的普通链接——把 API 留给你能掌控的时机。

4. 应用内评价:不能变通的设计红线

这张卡片属于 Play,不属于你的设计系统。要原样呈现:不得改动尺寸、透明度、形状或任何其他属性;不得在卡片上或卡片周围加蒙层;卡片与卡片背景必须处于最上层。卡片一旦出现,也绝不能由程序移除——它只会被用户的明确操作或 Play 商店的内部机制关闭。

代码层面,要等评价流程结束后再让应用继续正常流程,例如再进入下一关。如果流程中出错,不要告知用户、也不要改变应用流程:回调完成之后照常继续即可。

5. 配额:为什么 launchReviewFlow 不能做成按钮

Play 对「向同一位用户展示评价弹窗的频率」有时间维度的配额限制,因此在短时间内(按 Google 自己的举例是不到一个月)重复调用 launchReviewFlow,可能根本不会显示任何东西。配额的具体数值属于实现细节,Google 可以在不通知的情况下调整。

正因为配额在动,你就不能写出「假定一定成功」的界面。专门做一个调用该 API 的行动按钮,正是 Google 明确点名的反模式:用户可能已经用完了配额,流程不出现,你的按钮看上去就是坏的。若确实需要一个「去评分」的点击入口,请改为跳转 Play 商店。把 API 留给那些请求符合预期、即使不弹窗也看不出来的时机。

6. 应用内评价的代码路径

按顺序三次调用即可。

7. 应用内更新:灵活更新还是立即更新

两种流程回答的是不同的产品问题。灵活更新在后台下载并可平滑监控状态,用户可以边用边下载,适合「新功能或性能优化,晚几分钟也无妨」的场景。立即更新是全屏流程,用户必须更新并重启才能继续使用,适用于关系到核心功能的更新;用户接受之后,安装与应用重启都由 Play 处理。

选择原则是:用能解决问题的最小流程。逐步升级本身是合理的——先温和提示,必要时再强制——但这件事应该体现在你的优先级与陈旧天数逻辑里,而不是实现阶段拍一次脑袋定死。

8. 陈旧天数与更新优先级:把「有多急」变成代码

有两个信号能告诉应用更新到底拖了多久。

有一个容易被忽略的细节:应用里看到的优先级,会综合「已安装版本」与「最新可用版本」之间的所有 versionCode,无论它们发布在哪条轨道上。举例:版本 1 发到正式轨道且未设优先级,版本 2 发到内部测试轨道并设优先级 5,版本 3 再发到正式轨道且未设优先级——正式用户从 1 更新到 3 时,依然会拿到优先级 5,因为版本 2 夹在中间。

另外要记住这个限制:上传到内部应用共享(internal app sharing)时不支持 inAppUpdatePriority,所以依赖优先级的流程无法用这种方式排练。

9. 启动更新流程并读懂回调结果

先查可用性。用 AppUpdateManagerFactory.create(context) 创建 AppUpdateManager,读取 appUpdateInfo,确认 updateAvailability() 为 UPDATE_AVAILABLE,并用 isUpdateTypeAllowed() 确认你要用的更新类型被允许。只有这些都成立,才用注册在 StartIntentSenderForResult 契约上的 Activity Result 启动器调用 startUpdateFlowForResult()。

每个 AppUpdateInfo 实例只能启动一次更新。更新失败后想重试,必须重新获取 AppUpdateInfo,再确认可用性与类型许可。回调会返回 RESULT_OK(已接受)、RESULT_CANCELED(被拒绝或取消)或 RESULT_IN_APP_UPDATE_FAILED(其他因素阻断了用户同意或更新本身)。立即更新时你可能永远看不到 RESULT_OK,因为控制权回到应用之前,更新通常已经装完了。

AppUpdateOptions 里还有一个 AllowAssetPackDeletion 标志,默认 false,用于在设备存储紧张时允许更新清理资源包。使用它要刻意:先确认该更新在标志为 false 时能否成功,再考虑打开,因为这个标志的作用就是删资源。

10. 灵活更新:监控、下载,然后重启

启动流程前注册 InstallStateUpdatedListener,不再需要更新时注销。状态为 DOWNLOADING 时可读取 bytesDownloaded() 与 totalBytesToDownload() 做真实进度条。当状态变为 DOWNLOADED,Play 不会替你重启应用——这正是灵活更新的意义:你要用通知或 Snackbar 告知用户「更新已就绪」,由用户确认后再调用 completeUpdate()。

调用的位置会改变体验:在前台调用时,平台显示全屏界面并在后台重启应用;在后台调用则静默完成安装。无论哪种情况,都要在应用的所有入口(通常是 onResume())检查是否仍有更新停留在 DOWNLOADED 状态并再次提醒——否则已下载的数据会一直占着用户的存储,却始终没有安装。

11. 立即更新:把卡住的流程接回来

用户接受立即更新后,Play 会在你的界面之上显示进度,并且即使用户关闭或结束应用,下载与安装也会在后台继续。这对更新是好事,对代码却有点尴尬:应用回到前台时,可能处在一个「流程从未正式结束」的状态里。

在 onResume() 里处理它。如果 updateAvailability() 返回 DEVELOPER_TRIGGERED_UPDATE_IN_PROGRESS,就再次调用 startUpdateFlowForResult() 把流程续上。用户拒绝或取消时,Play 界面会关闭,接下来由你的应用决定:如果能不带更新继续运行,就让他继续并稍后再提示;如果确实不能,就在重新发起流程前用平实的语言说明原因,让这次重启是被理解的,而不是被当成崩溃循环。

12. 在真机上测试这两个 API

大多数「集成坏了」其实只是测试方式的问题。应用内更新的标准做法是内部应用共享:先确保测试设备上装着一个支持应用内更新、且来自内部应用共享链接的版本;再上传一个 versionCode 更高的版本;在设备上点开新版本的共享链接,但不要安装在随后出现的 Play 页面上;然后从桌面启动应用——此时更新就应该向你的应用提供出来了。

如果仍然没有,按四个常见原因排查:账号必须拥有该应用(也就是至少从 Play 下载过一次);测试包必须与 Play 上的版本共用同一个 applicationId 与签名密钥;已安装版本的 versionCode 必须低于待更新版本;以及内部应用共享不支持 inAppUpdatePriority,所以依赖优先级的流程在那里表现会不一样。

对于评价功能,测试时最大的差别在于公开性:在封闭测试轨道上,收集到的星级与评论会私下给到开发者,不会公开展示。它适合验证集成与时机是否正确,但不能当作真实评分变化的替代指标。

13. 上线之后盯什么

评价提示应该让评分数量缓慢变化,而不是与某次发布同步出现尖峰:尖峰是时机效应,不是质量变化,常见成因是提示被放在了会话过早的位置。更新方面,按周观察活跃用户停留在最新 versionCode 的比例——灵活更新应当让这个数字上升而不影响平均评分,同时减少来自旧版本包的错误反馈。

如果提示与卸载量正相关,或者招来带怒气的差评,答案绝不是「提示得更勤」或「提示得更早」。把触发点往用户旅程的后段挪,挪到应用的价值已经被证明之后。

正在规模化运营开发者账号?运维这一块交给我们。

点击选择文件 · 右键「粘贴」或按 Ctrl/⌘+V 直接粘贴截图

也可以直接拖拽文件到此处。

我们会回复你填写的邮箱,信息仅用于本次咨询。

✔ 已提交

我们已收到你的信息,会在 24 小时内回复。

也可发邮件给 expert@kapps.store
← 返回修改