Test Store 概述
0:02:00欢迎来到 Android 版 RevenueCat Test Store 设置指南!
测试应用内购买一直是一个具有挑战性的任务。您需要配置沙盒账户、创建测试产品、等待应用审核,还要处理不稳定的网络条件。RevenueCat 的 Test Store 通过提供确定性、快速且可靠的测试环境,消除了这些痛点。
什么是 Test Store?
Test Store 是 RevenueCat 内置的测试环境,允许您在不连接 Google Play 商店的情况下测试应用内购买流程。它会自动为每个新的 RevenueCat 项目进行配置,让您完全控制购买结果。
您将学到什么
本 Codelab 将指导您完成为 Android 开发设置和使用 RevenueCat Test Store 的完整过程。您将从在 RevenueCat 仪表板中启用 Test Store 并配置 Android 应用程序使用 Test Store API 密钥开始。然后,您将学习如何使用确定性结果测试购买流程、为应用内购买逻辑编写自动化单元测试,以及使用 GitHub Actions 将这些测试集成到您的 CI/CD 流水线中。
Test Store 的优势
Test Store 彻底改变了您测试应用内购买的方式。与传统测试方法需要等待 Google Play 配置或应用审批不同,Test Store 提供即时测试功能。您可以完全确定性地控制购买结果:交易是成功、失败还是取消完全由您决定。这意味着不再需要处理不稳定的网络连接或不可靠的沙盒环境。
当您开始编写自动化测试时,真正的力量就显现出来了。使用 Test Store,您可以为购买逻辑构建可靠的单元测试,这些测试在任何环境中都能一致运行,包括像 GitHub Actions 这样的 CI/CD 系统。这使您能够快速迭代购买流程,在几秒钟内而不是几分钟或几小时内测试更改。
前提条件
在开始之前,请确保您具备:
- 一个 RevenueCat 账户(在 revenuecat.com 免费注册)
- 已集成 RevenueCat SDK(9.0.0 或更高版本)的 Android 项目
- Kotlin 和 Android 开发的基础知识
- 熟悉 Jetpack Compose(可选,用于 UI 示例)
在仪表板中启用 Test Store
0:03:00第一步是在 RevenueCat 仪表板中启用 Test Store 并获取您的 Test Store API 密钥。
访问仪表板
首先登录您的 RevenueCat 仪表板,然后导航到左侧边栏菜单中的 Apps & providers 部分。这里是您可以找到所有已连接的应用和可用商店集成的地方。
创建您的 Test Store
在 Apps & providers 部分,在可用的提供商中找到 Test Store 选项。Test Store 会自动为每个 RevenueCat 项目配置,因此您只需点击 Create Test Store 或 Enable Test Store 来激活它。设置是即时的,无需等待审批或配置同步。
获取您的 API 密钥
启用 Test Store 后,点击应用列表中的 Test Store 条目查看其详细信息。在这里您会找到您的 Test Store API 密钥,它以前缀 test_ 开头。这个密钥的功能与常规 RevenueCat API 密钥相同,但有一个关键区别:它将所有购买请求路由到 Test Store 而不是 Google Play,让您完全控制测试环境。
理解 API 密钥分离: Test Store API 密钥与您的生产和沙盒密钥完全分开。这种分离是有意为之的,对安全性很重要。永远不要在生产构建中使用 Test Store 密钥;它们只应在调试和测试环境中使用。如果需要针对不同的测试场景,您可以为每个项目创建多个 Test Store 配置。
下一步
现在您已经有了 Test Store API 密钥,您可以准备配置 Android 应用程序以使用 Test Store 进行测试了。
在 Android 应用中配置 Test Store
0:05:00现在让我们配置您的 Android 应用程序以使用 Test Store。关键是在运行测试时使用 Test Store API 密钥而不是生产 API 密钥。
步骤 1:创建 BuildConfig 字段
将 Test Store API 密钥配置添加到您的应用 build.gradle.kts 中:
android {
defaultConfig {
// 您现有的配置
// 为调试构建添加 Test Store API 密钥
buildConfigField("String", "REVENUECAT_TEST_STORE_API_KEY", "\"test_YOUR_KEY_HERE\"\"")
}
buildTypes {
debug {
// 调试构建使用 Test Store
buildConfigField("String", "REVENUECAT_API_KEY", "\"test_YOUR_KEY_HERE\"\"")
}
release {
// 发布构建使用生产 API 密钥
buildConfigField("String", "REVENUECAT_API_KEY", "\"goog_YOUR_PRODUCTION_KEY\"\"")
}
}
}步骤 2:使用 Test Store 初始化 SDK
更新您的 Application 类以根据构建类型使用适当的 API 密钥:
class MyApplication : Application() {
override fun onCreate() {
super.onCreate()
// 初始化 RevenueCat SDK
val apiKey = BuildConfig.REVENUECAT_API_KEY
val builder = PurchasesConfiguration.Builder(this, apiKey)
Purchases.configure(
builder
.purchasesAreCompletedBy(PurchasesAreCompletedBy.REVENUECAT)
.appUserID(null)
.diagnosticsEnabled(true)
.build()
)
// 为测试构建启用调试日志
if (BuildConfig.DEBUG) {
Purchases.logLevel = LogLevel.DEBUG
}
}
}步骤 3:环境特定配置
对于更高级的设置,您可以创建一个配置类:
object RevenueCatConfig {
fun getApiKey(context: Context): String {
return if (isTestEnvironment()) {
BuildConfig.REVENUECAT_TEST_STORE_API_KEY
} else {
BuildConfig.REVENUECAT_API_KEY
}
}
private fun isTestEnvironment(): Boolean {
// 检查是否在测试环境中运行
return try {
Class.forName("androidx.test.espresso.Espresso")
true
} catch (e: ClassNotFoundException) {
false
} || BuildConfig.DEBUG
}
}然后在初始化中使用它:
val apiKey = RevenueCatConfig.getApiKey(this)
Purchases.configure(
PurchasesConfiguration.Builder(this, apiKey)
.purchasesAreCompletedBy(PurchasesAreCompletedBy.REVENUECAT)
.build()
)验证
要验证 Test Store 是否正常工作:
- 在调试模式下运行您的应用
- 检查日志中是否有
"Purchases SDK initialized with Test Store" - SDK 会指示它连接到 Test Store 而不是 Google Play
交互式测试购买流程
0:05:00启用 Test Store 后,您现在可以完全控制购买流程的结果来进行测试。当 Test Store 显示其购买对话框时,您决定结果。
理解 Test Store 购买对话框
当您使用 Test Store 发起购买时,您会看到一个自定义的 Test Store 对话框,而不是标准的 Google Play 购买界面。此对话框像真正的购买对话框一样显示产品详情和价格,但有一个关键区别:您可以控制结果。对话框提供三个明确的选项:购买成功模拟完成的交易,购买失败测试支付失败,以及取消模拟用户取消。这种确定性行为正是 Test Store 如此强大的原因。
测试成功流程
让我们测试一个成功的购买流程:
suspend fun purchaseProduct(activity: Activity) {
try {
// 从 Test Store 获取产品
val products = Purchases.sharedInstance.awaitGetProducts(
productIds = listOf("premium_monthly")
)
// 发起购买
val purchaseResult = Purchases.sharedInstance.awaitPurchase(
purchaseParams = PurchaseParams.Builder(
activity = activity,
storeProduct = products.first()
).build()
)
// 检查结果
val customerInfo = purchaseResult.customerInfo
val isPremium = customerInfo.entitlements["premium"]?.isActive == true
if (isPremium) {
// 购买成功!
showPremiumContent()
}
} catch (e: PurchasesException) {
// 处理错误
handlePurchaseError(e)
}
}测试正常路径:像平常一样运行您的应用并触发购买流程。当 Test Store 对话框出现时,点击"购买成功"。您的应用应该立即授予高级访问权限,您可以验证权益是否正确更新。这让您可以快速验证成功流程是否正常工作,无需真实的支付方式或沙盒账户。
测试失败场景
现在测试您的应用如何处理失败:
fun handlePurchaseError(error: PurchasesException) {
when (error.code) {
PurchasesErrorCode.PURCHASE_CANCELLED_ERROR -> {
// 用户取消 - 不显示错误
Log.d("Purchase", "用户取消了购买")
}
PurchasesErrorCode.PURCHASE_INVALID_ERROR -> {
// 无效购买
showError("此购买不可用")
}
PurchasesErrorCode.PAYMENT_PENDING_ERROR -> {
// 支付待处理(例如,等待家长批准)
showPendingMessage()
}
else -> {
// 其他错误
showError("购买失败: ${error.message}")
}
}
}测试错误处理:再次触发购买流程,但这次当 Test Store 对话框出现时,点击"购买失败"。您的应用应该优雅地处理错误,向用户显示适当的错误消息。确认用户没有获得高级访问权限,并且应用的状态保持一致。这对于确保您的错误处理逻辑在生产环境中正确工作至关重要。
测试取消
@Composable
fun PaywallScreen(onDismiss: () -> Unit) {
val scope = rememberCoroutineScope()
var isPurchasing by remember { mutableStateOf(false) }
Button(
onClick = {
scope.launch {
isPurchasing = true
try {
purchaseProduct(LocalContext.current as Activity)
} catch (e: PurchasesException) {
if (e.code == PurchasesErrorCode.PURCHASE_CANCELLED_ERROR) {
// 用户取消 - 只需关闭
onDismiss()
}
}
isPurchasing = false
}
},
enabled = !isPurchasing
) {
Text(if (isPurchasing) "处理中..." else "订阅")
}
}测试用户取消:打开您的付费墙并点击订阅按钮。当 Test Store 对话框出现时,点击"取消"模拟用户退出购买。您的付费墙应该干净地关闭,不显示任何错误消息(取消是正常的用户操作,不是错误状态)。验证没有记录购买,并且您的应用状态保持不变。
关键要点
Test Store 的美妙之处在于其确定性控制。您决定每次购买尝试的确切结果。这意味着您可以在几分钟内彻底测试所有场景(成功、失败和取消),无需真实的支付方式,也不需要处理沙盒账户的延迟和复杂性。当您准备好与 Google Play 集成时,您将对自己的购买处理逻辑非常有信心。
编写自动化单元测试
0:08:00Test Store 最强大的功能之一是支持您的应用内购买逻辑的自动化单元测试。让我们编写能够在 CI/CD 中可靠运行的测试。
步骤 1:添加测试依赖项
将以下内容添加到您的 build.gradle.kts:
dependencies {
// RevenueCat SDK
implementation("com.revenuecat.purchases:purchases:9.20.2")
// 测试依赖项
testImplementation("junit:junit:4.13.2")
testImplementation("org.jetbrains.kotlinx:kotlinx-coroutines-test:1.7.3")
testImplementation("io.mockk:mockk:1.13.8")
androidTestImplementation("androidx.test.ext:junit:1.1.5")
androidTestImplementation("androidx.test:runner:1.5.2")
}步骤 2:创建购买仓库
首先,让我们创建一个可测试的购买仓库:
interface PurchaseRepository {
suspend fun getProducts(productIds: List<String>): List<StoreProduct>
suspend fun purchaseProduct(activity: Activity, product: StoreProduct): CustomerInfo
suspend fun getCustomerInfo(): CustomerInfo
}
class PurchaseRepositoryImpl(
private val purchases: Purchases = Purchases.sharedInstance
) : PurchaseRepository {
override suspend fun getProducts(productIds: List<String>): List<StoreProduct> {
return purchases.awaitGetProducts(productIds)
}
override suspend fun purchaseProduct(
activity: Activity,
product: StoreProduct
): CustomerInfo {
val result = purchases.awaitPurchase(
PurchaseParams.Builder(activity, product).build()
)
return result.customerInfo
}
override suspend fun getCustomerInfo(): CustomerInfo {
return purchases.awaitCustomerInfo()
}
}步骤 3:创建带有业务逻辑的 ViewModel
class PaywallViewModel(
private val repository: PurchaseRepository
) : ViewModel() {
private val _state = MutableStateFlow<PaywallState>(PaywallState.Loading)
val state: StateFlow<PaywallState> = _state.asStateFlow()
fun loadProducts() {
viewModelScope.launch {
try {
val products = repository.getProducts(listOf("premium_monthly"))
_state.value = PaywallState.Success(products)
} catch (e: Exception) {
_state.value = PaywallState.Error(e.message ?: "未知错误")
}
}
}
fun purchaseProduct(activity: Activity, product: StoreProduct) {
viewModelScope.launch {
_state.value = PaywallState.Purchasing
try {
val customerInfo = repository.purchaseProduct(activity, product)
val isPremium = customerInfo.entitlements["premium"]?.isActive == true
if (isPremium) {
_state.value = PaywallState.PurchaseSuccess
} else {
_state.value = PaywallState.Error("购买已完成但权益未激活")
}
} catch (e: PurchasesException) {
when (e.code) {
PurchasesErrorCode.PURCHASE_CANCELLED_ERROR -> {
_state.value = PaywallState.PurchaseCancelled
}
else -> {
_state.value = PaywallState.Error(e.message)
}
}
}
}
}
}
sealed class PaywallState {
object Loading : PaywallState()
data class Success(val products: List<StoreProduct>) : PaywallState()
object Purchasing : PaywallState()
object PurchaseSuccess : PaywallState()
object PurchaseCancelled : PaywallState()
data class Error(val message: String) : PaywallState()
}步骤 4:编写单元测试
现在使用 Test Store 创建单元测试:
@RunWith(AndroidJUnit4::class)
class PaywallViewModelTest {
private lateinit var repository: PurchaseRepository
private lateinit var viewModel: PaywallViewModel
@Before
fun setup() {
// 使用 Test Store API 密钥初始化 RevenueCat
Purchases.configure(
PurchasesConfiguration.Builder(
ApplicationProvider.getApplicationContext(),
"test_YOUR_KEY_HERE"
).build()
)
repository = PurchaseRepositoryImpl()
viewModel = PaywallViewModel(repository)
}
@Test
fun testLoadProducts_Success() = runTest {
// Given: ViewModel 已初始化
// When: 加载产品
viewModel.loadProducts()
// 等待状态更新
advanceUntilIdle()
// Then: 产品应该加载成功
val state = viewModel.state.value
assertTrue(state is PaywallState.Success)
assertFalse((state as PaywallState.Success).products.isEmpty())
}
@Test
fun testPurchaseProduct_Success() = runTest {
// Given: 产品已加载
viewModel.loadProducts()
advanceUntilIdle()
val state = viewModel.state.value as PaywallState.Success
val product = state.products.first()
// When: 用户购买产品并且 Test Store 对话框显示"购买成功"
// 注意:在实际测试中,您需要与 Test Store 对话框交互
viewModel.purchaseProduct(mockActivity, product)
advanceUntilIdle()
// Then: 购买应该成功并且权益应该激活
val finalState = viewModel.state.value
assertTrue(finalState is PaywallState.PurchaseSuccess)
}
@Test
fun testPurchaseProduct_Cancelled() = runTest {
// Given: 产品已加载
viewModel.loadProducts()
advanceUntilIdle()
val state = viewModel.state.value as PaywallState.Success
val product = state.products.first()
// When: 用户在 Test Store 对话框中取消购买
viewModel.purchaseProduct(mockActivity, product)
advanceUntilIdle()
// Then: 状态应该指示取消
val finalState = viewModel.state.value
assertTrue(finalState is PaywallState.PurchaseCancelled)
}
}步骤 5:基于 Mock 的测试替代方案
为了获得更多控制,您可以模拟仓库:
class PaywallViewModelMockTest {
private lateinit var mockRepository: PurchaseRepository
private lateinit var viewModel: PaywallViewModel
@Before
fun setup() {
mockRepository = mockk()
viewModel = PaywallViewModel(mockRepository)
}
@Test
fun testPurchaseSuccess() = runTest {
// Given: 模拟成功购买
val mockProduct = mockk<StoreProduct>()
val mockCustomerInfo = mockk<CustomerInfo> {
every { entitlements["premium"]?.isActive } returns true
}
coEvery {
mockRepository.purchaseProduct(any(), mockProduct)
} returns mockCustomerInfo
// When: 发起购买
viewModel.purchaseProduct(mockk(), mockProduct)
advanceUntilIdle()
// Then: 状态应该为成功
assertTrue(viewModel.state.value is PaywallState.PurchaseSuccess)
}
@Test
fun testPurchaseFailed() = runTest {
// Given: 模拟失败购买
val mockProduct = mockk<StoreProduct>()
coEvery {
mockRepository.purchaseProduct(any(), mockProduct)
} throws PurchasesException(
PurchasesErrorCode.PAYMENT_PENDING_ERROR,
"支付待处理"
)
// When: 发起购买
viewModel.purchaseProduct(mockk(), mockProduct)
advanceUntilIdle()
// Then: 状态应该显示错误
val state = viewModel.state.value
assertTrue(state is PaywallState.Error)
assertTrue((state as PaywallState.Error).message.contains("pending"))
}
}为什么这种方法有效
这种测试方法消除了测试应用内购买的传统痛点。因为 Test Store 没有网络依赖,您的测试每次都能可靠运行。不再有因连接问题导致的不稳定失败。测试在几秒钟而不是几分钟内执行,让您在开发过程中获得快速反馈。您可以在所有场景(包括难以用真实支付系统重现或耗时的边缘情况)中实现完整的测试覆盖。
我们构建的架构(使用仓库模式将业务逻辑与 SDK 分离)使这些测试既快速又可维护。您可以在任何 CI/CD 环境(如 GitHub Actions)中运行它们,在 bug 到达生产环境之前捕获它们。
在 CI/CD 中运行测试
0:04:00现在让我们配置您的测试以在 GitHub Actions 中自动运行,确保每次代码更改时您的购买逻辑都保持可靠。
步骤 1:创建 GitHub Actions 工作流
创建 .github/workflows/android-tests.yml:
name: Android Tests
on:
push:
branches: [ main, develop ]
pull_request:
branches: [ main, develop ]
jobs:
test:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Set up JDK 17
uses: actions/setup-java@v4
with:
java-version: '17'
distribution: 'temurin'
- name: Cache Gradle packages
uses: actions/cache@v3
with:
path: |
~/.gradle/caches
~/.gradle/wrapper
key: ${{ runner.os }}-gradle-${{ hashFiles('**__RCPH_0_HPRC__gradle-wrapper.properties') }}
restore-keys: |
${{ runner.os }}-gradle-
- name: Grant execute permission for gradlew
run: chmod +x gradlew
- name: Run unit tests
env:
REVENUECAT_TEST_STORE_API_KEY: ${{ secrets.REVENUECAT_TEST_STORE_API_KEY }}
run: ./gradlew testDebugUnitTest
- name: Upload test results
if: always()
uses: actions/upload-artifact@v3
with:
name: test-results
path: app/build/test-results/
- name: Upload test reports
if: always()
uses: actions/upload-artifact@v3
with:
name: test-reports
path: app/build/reports/tests/步骤 2:将 Test Store API 密钥添加到 GitHub Secrets
- 转到您的 GitHub 仓库
- 导航到 Settings → Secrets and variables → Actions
- 点击 New repository secret
- 名称:
REVENUECAT_TEST_STORE_API_KEY - 值:您的 Test Store API 密钥(例如
test_xxxxx) - 点击 Add secret
步骤 3:配置 Gradle 使用 Secret
更新您的 build.gradle.kts 以使用环境变量:
android {
defaultConfig {
// 从环境获取 Test Store API 密钥或使用占位符
val testStoreApiKey = System.getenv("REVENUECAT_TEST_STORE_API_KEY")
?: "test_placeholder"
buildConfigField("String", "REVENUECAT_TEST_STORE_API_KEY", "\"$testStoreApiKey\"\"")
}
}步骤 4:使用模拟器运行仪器测试
对于更高级的测试,添加仪器测试:
instrumented-test:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Set up JDK 17
uses: actions/setup-java@v4
with:
java-version: '17'
distribution: 'temurin'
- name: Enable KVM (for faster emulator)
run: |
echo 'KERNEL=="kvm", GROUP="kvm", MODE="0666", OPTIONS+="static_node=kvm"' | sudo tee /etc/udev/rules.d/99-kvm4all.rules
sudo udevadm control --reload-rules
sudo udevadm trigger --name-match=kvm
- name: Grant execute permission for gradlew
run: chmod +x gradlew
- name: Run instrumented tests
uses: reactivecircus/android-emulator-runner@v2
env:
REVENUECAT_TEST_STORE_API_KEY: ${{ secrets.REVENUECAT_TEST_STORE_API_KEY }}
with:
api-level: 29
target: default
arch: x86_64
profile: Nexus 6
script: ./gradlew connectedDebugAndroidTest
- name: Upload instrumented test results
if: always()
uses: actions/upload-artifact@v3
with:
name: instrumented-test-results
path: app/build/outputs/androidTest-results/验证您的设置
提交并推送您的更改以触发工作流。前往 GitHub 仓库的 Actions 标签页观看您的测试自动运行。您会看到实时进度,工作流检出您的代码、设置环境并运行测试套件。几分钟内,您就会知道所有测试是否在 CI 环境中通过。
自动化测试的力量
一旦设置完成,每个拉取请求在合并前都会自动验证。如果任何更改破坏了您的购买逻辑,您会立即收到反馈,无需手动测试每个场景。Test Store 确保您的测试在每次运行中产生一致的结果,消除了不稳定测试的烦恼。这创建了一个质量门禁,防止有 bug 的代码进入您的主分支,同时节省了大量原本用于重复手动测试的时间。
最佳实践与生产环境设置
0:03:00现在您已经设置了 Test Store,让我们介绍最佳实践以及如何在 Test Store 和生产环境之间切换。
环境分离
始终保持 Test Store 和生产密钥分开:
object RevenueCatKeys {
// Test Store - 仅用于测试
const val TEST_STORE_KEY = "test_xxxxx"
// Google Play - 用于生产
const val GOOGLE_PLAY_KEY = "goog_xxxxx"
fun getApiKey(isTestMode: Boolean): String {
return if (isTestMode) TEST_STORE_KEY else GOOGLE_PLAY_KEY
}
}构建变体配置
使用构建变体在环境之间自动切换:
android {
buildTypes {
debug {
buildConfigField("String", "RC_API_KEY", "\"test_xxxxx\"\"")
buildConfigField("Boolean", "USE_TEST_STORE", "true")
}
release {
buildConfigField("String", "RC_API_KEY", "\"goog_xxxxx\"\"")
buildConfigField("Boolean", "USE_TEST_STORE", "false")
}
}
flavorDimensions += "environment"
productFlavors {
create("dev") {
dimension = "environment"
buildConfigField("String", "RC_API_KEY", "\"test_xxxxx\"\"")
}
create("staging") {
dimension = "environment"
buildConfigField("String", "RC_API_KEY", "\"test_xxxxx\"\"")
}
create("prod") {
dimension = "environment"
buildConfigField("String", "RC_API_KEY", "\"goog_xxxxx\"\"")
}
}
}构建全面的测试策略
应用内购买的健全测试策略应该遵循金字塔方法。首先使用 Test Store 进行单元测试,以在隔离环境中验证您的购买逻辑。这些测试运行快速,能够及早发现大多数问题。在此基础上使用 Test Store 构建集成测试,以端到端验证完整的购买流程。一旦您对实现有信心,就转向 Google Play 沙盒进行手动测试以验证平台集成。最后,用真实支付进行小规模生产测试,以确保一切在实际环境中正常工作。
在 Test Store 和沙盒之间选择
在初始开发和迭代过程中,Test Store 是您最好的朋友。它非常适合快速原型设计购买流程、编写单元和集成测试以及测试错误处理和边缘情况。即时反馈循环使其成为需要可靠、快速结果的 CI/CD 自动化测试的理想选择。
当您需要测试 Test Store 无法模拟的平台特定功能时,切换到 Google Play 沙盒。这包括待处理交易(如等待家长批准的交易)、收据验证细节、订阅续订周期和区域特定定价。将沙盒视为您的预生产验证环境。在您的核心逻辑稳固并需要验证 Google Play 集成后使用它。
安全最佳实践
永远不要在生产环境中暴露您的 Test Store API 密钥:
// 错误:硬编码密钥
val apiKey = "test_xxxxx"
// 正确:基于环境的配置
val apiKey = if (BuildConfig.DEBUG) {
BuildConfig.TEST_STORE_API_KEY
} else {
BuildConfig.GOOGLE_PLAY_API_KEY
}
// 更好:检查测试环境
val apiKey = when {
isRunningInTests() -> BuildConfig.TEST_STORE_API_KEY
BuildConfig.DEBUG -> BuildConfig.TEST_STORE_API_KEY
else -> BuildConfig.GOOGLE_PLAY_API_KEY
}日志和调试
启用适当的日志级别:
if (BuildConfig.USE_TEST_STORE) {
Purchases.logLevel = LogLevel.VERBOSE
Log.d("RevenueCat", "使用 Test Store 进行测试")
} else if (BuildConfig.DEBUG) {
Purchases.logLevel = LogLevel.DEBUG
} else {
Purchases.logLevel = LogLevel.INFO
}过渡到生产环境
在发布您的应用之前,请确保您已完成彻底的检查清单。所有测试都应该通过 Test Store,并且您应该已经手动验证了与 Google Play 沙盒的集成。仔细检查您的构建变体是否正确配置以在每个环境中使用正确的 API 密钥。生产 API 密钥必须安全存储,永远不要提交到版本控制。验证 Test Store 密钥已从发布构建中完全删除;它们只应存在于调试配置中。确保日志已适当配置(调试时详细,生产时最小),并确认您的错误处理已在所有场景中测试过。
总结
恭喜!您已成功为 Android 设置了 RevenueCat 的 Test Store。在本 Codelab 中,您学习了如何在 RevenueCat 仪表板中启用 Test Store、在 Android 应用程序中配置 Test Store API 密钥、使用确定性结果测试购买流程、为购买逻辑编写自动化单元测试、在 GitHub Actions 等 CI/CD 环境中运行这些测试,以及遵循环境分离的最佳实践。
关键要点
Test Store 从根本上改变了您处理应用内购买测试的方式。不再需要与沙盒账户搏斗和处理不稳定的网络依赖测试。通过对购买结果的确定性控制,您可以编写可靠的测试,让您对自己的实现真正有信心。CI/CD 集成意味着每次代码更改都会持续验证您的购买逻辑,使您能够在几秒钟内而不是几小时内迭代购买流程。最重要的是,您将在购买相关的 bug 到达生产环境之前捕获它们,保护您的收入和用户体验。
下一步
现在您已经设置了 Test Store,是时候在此基础上构建了。首先编写覆盖所有购买场景的全面测试。不要只测试正常路径。将这些测试集成到您的 CI/CD 流水线中,以便在每个拉取请求上自动运行。使用不同的失败模式彻底测试您的错误处理,以确保您的应用能够优雅降级。当您准备好后,过渡到 Google Play 沙盒进行平台特定测试,以验证订阅续订等功能。最后,满怀信心地发布,因为您知道您的购买逻辑在每个步骤都经过了彻底验证。
其他资源
RevenueCat Test Store 博客文章 RevenueCat Android SDK 文档 测试指南 GitHub: Cat Paywall Compose祝测试愉快!