任何在 Google Play 上卖东西的安卓应用——订阅、一次性解锁、金币包——包里都带着一份 Google Play Billing Library(结算库)。它没有永久生命力:Google 对每个大版本执行固定两年的淘汰时钟,一旦你的版本被淘汰,应用仍能运行,但你再也提交不了更新。截至 2026 年 8 月 31 日,Play 接受的最低版本是 Billing Library 8;所有仍用 7 或更早版本构建的更新,只剩最后一个窗口:2026 年 11 月 1 日的延期截止日。

下面是有操作价值的那一版:淘汰时间表今天到底怎么写的、怎么查清某个 APK 到底带的是哪个版本、从 7 跳到 8 或 9 时哪些 API 改名会让编译直接失败、延期申请表在哪里,以及发包前必须测什么。

四个数字决定这次迁移: 2 年——自 Google 在 2019 年 I/O 公布该政策以来,每个 Play Billing Library 大版本适用的淘汰周期。2026 年 8 月 31 日——新应用与更新必须使用 8 或更高版本的日期(即 v7 的淘汰日)。2026 年 11 月 1 日——同一版本的延期截止日。8——今天 Play 在发布新版本时最低接受的版本号。

1. 今天这条截止线的实际状态

Google 官方 Play Billing Library 版本淘汰页顶部的横幅原文是:「By Aug 31, 2026, all new apps and updates to existing apps must use Billing Library version 8 or later. If you need more time to update your app, you can request an extension until Nov 1, 2026.」这一句就是全部规则,而它包含两半,常被混为一谈。

第一半是发布限制,不是下架:仍带被淘汰版本的应用对已安装用户继续正常工作,但 Play 不接受你的新版本。淘汰问答页把推论写得很明确——不再维护的 APK 不需要更新,而新应用和更新必须使用受支持的版本。所以风险不是「应用从商店消失」,而是「修复包、新的商店信息实验、合规更新,都发不出去」。

第二半是逃生门:延期。它必须在 Play Console 内申请,而且是对着同一个固定日历日批准的,而不是重新起算——所以对 2026 年 9 月下旬仍在 v7 的团队,真正的问题不是「还有没有时间」,而是「延期到底申请了没有」。

2. 淘汰时钟是固定的,并且提前公布

Google 把整张淘汰时间表都公布了,它更应该被当成排期表来读,而不是警告。每个大版本的「新应用与更新」截止日都是 8 月 31 日,延期截止日都是 11 月 1 日,间隔两年:

由此得出两个结论。第一,2025 年就已经落后两个版本的应用现在落后三个,而今天做这件事的工作量与当时一模一样。第二,这是一条永久性的维护事项,不是一次性项目:无论这次选哪个版本,两年内你还会回到这里。把版本升级并入常规发版节奏,比被 Console 警告推着走要便宜得多。

3. 第一步——查清你的构建实际带的是哪个版本

从 build.gradle 开始。结算库以 com.android.billingclient:billing 依赖形式声明,它的版本号就是答案:

dependencies {
    def billingVersion = "8.3.0"
    implementation "com.android.billingclient:billing:$billingVersion"
}

淘汰问答页补充了一个关键细节:这些依赖只出现在声明了 com.android.vending.BILLING 权限的 APK 里。在多模块项目,或一个由若干应用共用旧模块的产品矩阵里,出问题的是声明了 billing 的那个构建,而不一定是你印象里的那个应用。要审计每一个带 billing 的 bundle,而不是你记得写过支付代码的那几个。

还有第二处检查,能解释「为什么已经升级了警告还在」。Play 是通过合并后的 AndroidManifest.xml 里的 com.google.android.play.billingclient.version 属性来识别版本。如果你已经升级了依赖、Console 却仍报旧版本,官方建议就是确认该属性是否存在——manifest 合并是它丢失的常见原因。

4. 第二步——定目标:版本 8 还是版本 9

官方要求是「version 8 or later」,也就是 8.x 与 9.x 都满足。这个取舍是真实的,应当有意识地做:

如果你也顺便在规划下一个周期:v8 自己的截止日是 2027 年 8 月 31 日,延期到 2027 年 11 月 1 日。今天直接迁到 9.1.0 能买到最长的缓冲期,而 v9 迁移指南本身就是写给从 7 或 8 直接过来的团队的。

5. 第三步——v7 到 v8 的迁移本体

按官方 Play Billing Library 8 迁移指南,升级是三件事加若干可选项。

第一件:改依赖版本。把 com.android.billingclient:billing 指向 8.0.0 或更高(除非有理由,否则用该线的最新补丁版,而不是 .0)。

第二件:处理改名的订阅 API。从 PBL 6 过来的代码编译会直接断在这里,替代项是等价的改名:

第三件:改 queryProductDetailsAsync。ProductDetailsResponseListener.onProductDetailsResponse 的签名有变更,你的实现必须跟着改。签名背后的行为变化比签名本身更重要:8.0.0 之前,取不到的商品干脆不返回;PBL 8 会把它们带回,并附带一个新的商品级状态码说明原因——商品不存在,或该用户没有可用优惠。如果你的界面以前是靠「没有返回」来推断「用户不符合资格」,现在必须去读状态码,而不是猜。

PBL 8 同时移除了以下 API(若你的代码仍在调用):queryPurchaseHistoryAsync(改用 Query Purchase History 中列出的替代方案)、querySkuDetailsAsync(改用 queryProductDetailsAsync)、无参数的 enablePendingPurchases()(改用 enablePendingPurchases(PendingPurchaseParams)),以及旧的 queryPurchasesAsync(String skuType, PurchasesResponseListener) 重载。从 v6 或更早直接跳到 v8 的读者,还需要把 enableAlternativeBilling/AlternativeBillingListener/AlternativeChoiceDetails 换成 enableUserChoiceBilling/UserChoiceBillingListener/UserChoiceDetails。

可选项,但值得做:BillingClient.Builder.enableAutoServiceReconnection() 让库自行重建与 Play 结算服务的连接,而不要求你在断连后再次调用 startConnection()——这是安卓上「点了购买按钮没反应」类反馈最常见的来源。同一版本还为预付费方案增加了待处理购买支持,并支持虚拟分期订阅。

6. 第四步——或者一步到位迁到 9.1.0

Play Billing Library 9 迁移指南面向从 7 或 8 过来的团队。除了把依赖升到 9.1.0,反复出现的主题是旧 SKU 词汇彻底退场(BillingClient.SkuType → ProductType、SkuDetails → ProductDetails、SkuDetailsParams → QueryProductDetailsParams、SkuDetailsResponseListener → ProductDetailsResponseListener、getSkuDetailsList/setSkuDetailsList → setProductDetailsParamsList),而其中一条直接落在订阅收入逻辑上:

如果你此前用 queryPurchaseHistoryAsync 判断用户是否符合免费试用资格,指南要求改用 ProductDetails.getSubscriptionOfferDetails() 来判断用户对哪些优惠符合资格。

v9 里还有三处小改动容易被漏掉。Play 商店被阻止时的处理变了:当 Play 商店应用本身被系统阻止(例如 OEM 定制的儿童模式),返回码从 ERROR 变为 BILLING_UNAVAILABLE,并附带「Play Store is blocked」的调试信息,且该行为需要 androidx.core 1.9 或更高版本。其次,DeveloperProvidedBillingDetails.getLinkUri() 现在标注为 @Nullable,任何未做 null 与空字符串判断就启动该 URI 的代码都是现成的崩溃点。第三,9.0.0 为「选择性涨价」增加了应用内提示,用户不必离开应用即可确认涨价——官方限定同一提示最多每 7 天展示一次。

7. 第五步——真需要时,才用延期申请

如果你的应用仍在发布不受支持的版本,Play Console 会给出警告。延期是从该警告的详情页申请的:打开 Policy status(政策状态),进入该警告,使用那里链接的延期表单。按官方说明,这是唯一渠道——没有邮件申请,对应版本在已公布的 11 月 1 日之后也没有第二延期。

把它当成一个已经固定的截止日之内的发货缓冲,而不是额外跑道。即使提交了延期,工作仍必须在 2026 年 11 月 1 日前完成;此后基于 v7 的新版本不再被接受——包括你可能正在等的那次、与本次政策完全无关的合规发版。

8. 第六步——发包前的验证

结算类回归不会以崩溃的形式出现,它表现为「付费用户买不了」。发布进正式轨道之前:

9. 新版本在收入侧给了什么

迁移是实打实的工作量,所以也该算清新版解锁了什么。PBL 8.0.0 把「in-app items」改名为 一次性商品,并为其增加多个购买选项与优惠,减少了「同一个东西按不同价位卖」所需创建的商品数量。它还为 launchBillingFlow() 增加了子返回码:PAYMENT_DECLINED_DUE_TO_INSUFFICIENT_FUNDS、USER_INELIGIBLE(用户不满足所配置的订阅优惠资格要求),以及默认值 NO_APPLICABLE_SUB_RESPONSE_CODE——「出了点问题」与「请先给卡充值」之间的差别就在这些码里。

2025 年 12 月的 8.2.x 与 8.3.0 增加了外部内容链接、外部优惠与外部支付 API,9.1.0 增加了 Billing Choice 相关 API。若你的路线图包含这些项目,升级版本是前置条件而不是另一个独立项目——这也是「既然已经在这段代码里,就顺便迁到 9.1.0」的实际理由。


参考来源