基于In-app Billing 5实现内购后禁用Admob广告的方案咨询
可行方案分析与实现建议
关于Product Flavors的适用性
Product Flavors是编译时区分不同版本的方案,适合做「免费版(带广告)」和「付费版(无广告)」两个独立安装包的场景,但你的需求是用户在同一个应用内完成内购后动态禁用广告,所以这个方案并不合适——它无法处理用户在应用内购买后实时切换状态的需求,反而会增加版本维护的成本。
推荐的实现方案
1. 本地存储内购状态(轻量方案)
无需复杂数据库,用SharedPreferences就能满足需求:
- 当用户完成内购并通过Google Play的签名验证后,在本地写入一个标记(比如
is_premium_user = true)。 - 签名验证是必须的,防止恶意篡改本地数据,你可以通过In-app Billing 5返回的
Purchase对象中的签名信息进行验证。
示例代码:
// 购买成功并验证后,写入SharedPreferences val sharedPref = context.getSharedPreferences("app_prefs", Context.MODE_PRIVATE) sharedPref.edit().putBoolean("is_premium_user", true).apply()
2. 广告加载的条件判断
在所有加载Admob广告的代码逻辑中,先读取本地存储的标记,决定是否加载广告:
val sharedPref = context.getSharedPreferences("app_prefs", Context.MODE_PRIVATE) val isPremium = sharedPref.getBoolean("is_premium_user", false) if (!isPremium) { // 加载Admob广告 adView.loadAd(AdRequest.Builder().build()) } else { // 隐藏广告容器或不执行加载逻辑 adView.visibility = View.GONE }
3. 同步内购状态(解决设备切换/数据清除问题)
用户换设备或清除应用数据后,本地标记会丢失,所以每次应用启动时,需要调用In-app Billing 5的接口查询用户的已购商品,同步状态:
billingClient.queryPurchasesAsync(QueryPurchasesParams.newBuilder().setProductType(BillingClient.ProductType.INAPP).build()) { billingResult, purchases -> if (billingResult.responseCode == BillingClient.BillingResponseCode.OK && purchases != null) { val hasValidPurchase = purchases.any { it.purchaseState == Purchase.PurchaseState.PURCHASED } val sharedPref = context.getSharedPreferences("app_prefs", Context.MODE_PRIVATE) sharedPref.edit().putBoolean("is_premium_user", hasValidPurchase).apply() } }
4. 订阅类内购的额外处理(如果适用)
如果你的内购是订阅类型,除了判断购买状态,还要检查订阅是否过期:
val isSubscriptionActive = purchases.any { it.purchaseState == Purchase.PurchaseState.PURCHASED && (it.isAutoRenewing || it.purchaseTime + it.subscriptionPeriodMillis >= System.currentTimeMillis()) }
关键注意事项
- 必须严格执行Google Play的签名验证,不要跳过这一步,否则会有被破解的风险。
- 不要仅依赖本地存储的标记,每次启动都要同步最新的购买状态,保证状态一致性。
- 如果是订阅,要处理订阅到期后重新显示广告的逻辑。
内容的提问来源于stack exchange,提问作者Taki
相关产品推荐
相关产品推荐

