FAQ
This section contains Kotlin code examples.
Q: How to fix the "Application is not verified yet" error?
A: This error occurs in the following cases:
- the app did not pass the moderation in the RuStore Console;
- the tested APK does not match the APK uploaded to the RuStore Console.
You can check the latter in the following manner.
applicationId
specified inbuild.gradle
must matchapplicationId
of the APK file you published in the [RuStore Console].(https://console.rustore.ru/sign-in).- the
keystore
signature must match the signature used to sign the app published in the RuStore Console. Make sure thatbuildType
you use (for example:debug
) uses the same signature as the published app (for example:release
).
Q: What does the AuthTokenException error mean?
A: SDK failed to authorize. Problem with the signature/package name/RuStore instance on the device.
Q: How to fix the Application signature not correct error?
A: Problem with signatures. Make sure that the keystore
signature matches the signatures you used to sign your app in the RuStore Console.
Q: How to fix "Purchase created earlier "..." in quantity ... in amount of ... rubles is being paid in another session".
A: This error occurs if there is an attempt to purchase a product for which another purchase was initiated but not finalized with the deletePurchase
or confirmPurchase
method.
It often happens when the purchase is interrupted without cancellation or confirmation called in purchaseProduct
due to incorrect process termination.
In such cases you need to cancel or confirm the incomplete purchases on app start or when your store is opened.
Below is the implementation example of the products list processing. Run this code on app start or when your store is opened.
val purchasesUseCase = billingClient.purchases
val purchases = purchasesUseCase.getPurchases().await().purchases.orEmpty()
purchases.forEach { purchase ->
val purchaseId = purchase.purchaseId
if (purchaseId != null) {
when (purchase.purchaseState) {
PurchaseState.CREATED, PurchaseState.INVOICE_CREATED -> {
purchasesUseCase.deletePurchase(purchaseId).await()
}
PurchaseState.PAID -> {
purchasesUseCase.confirmPurchase(purchaseId).await()
}
else -> Unit
}
}
}
Purchase cancellation and confirmations are also done in purchaseProduct()
.
You can configure the purchase processing in purchaseProduct()
to finalize purchases the following way.
private fun purchaseProduct(product: Product) {
val purchasesUseCase = billingClient.purchases
purchasesUseCase.purchaseProduct(product.productId)
.addOnSuccessListener { paymentResult ->
handlePaymentResult(paymentResult, product)
}
.addOnFailureListener {
// Handle error
}
}
private fun handlePaymentResult(paymentResult: PaymentResult, product: Product) {
when (paymentResult) {
is PaymentResult.InvalidPurchase -> {
paymentResult.purchaseId?.let { deletePurchase(it) }
}
is PaymentResult.PurchaseResult -> {
when (paymentResult.finishCode) {
PaymentFinishCode.SUCCESSFUL_PAYMENT -> {
if (product.productType == ProductType.CONSUMABLE) {
confirmPurchase(paymentResult.purchaseId)
}
}
PaymentFinishCode.CLOSED_BY_USER,
PaymentFinishCode.UNHANDLED_FORM_ERROR,
PaymentFinishCode.PAYMENT_TIMEOUT,
PaymentFinishCode.DECLINED_BY_SERVER,
PaymentFinishCode.RESULT_UNKNOWN -> {
deletePurchase(paymentResult.purchaseId) }
}
}
else -> Unit
}
}
Purchase confirmation and cancellation is described in section Purchase confirmation and cancellation scenario».
Q: How to perform server-side validation of a purchase?
A: First, you need to get subscriptionToken
that is itself a purchase identifier, the process is described in section Server validation.
Then, send this subscriptionToken
to your backend where you can request the information about the purchase using the method for receiving subscription data by subscription token.
Q: How to fix 404 when calling confirmPurchase
or deletePurchase
?
A: Make sure you pass purchaseId
to the confirmPurchase
and deletePurchase
methods parameter (see below).
val purchasesUseCase = billingClient.purchases
val purchases = purchasesUseCase.getPurchases().await().purchases.orEmpty()
purchases.forEach { purchase ->
val purchaseId = purchase.purchaseId
if (purchaseId != null) {
when(purchase.purchaseState) {
PurchaseState.CREATED, PurchaseState.INVOICE_CREATED -> {
// purchasesUseCase.deletePurchase(purchaseId = purchase.productId).await() WRONG
purchasesUseCase.deletePurchase(purchaseId = purchaseId).await() // CORRECT
}
PurchaseState.PAID -> {
// purchasesUseCase.confirmPurchase(purchaseId = purchase.productId).await() WRONG
purchasesUseCase.confirmPurchase(purchaseId = purchaseId).await() // CORRECT
}
else -> Unit
}
}
}
Q: How to fix the "Method unavailable" error
A: consoleApplicationId
must match the application code from the RuStore Console (exanple: https://console.rustore.ru/apps/123456
).
Q: How does one cancel a subscription?
A: There is no method for subscription cancellation, you can only cancel auto-renewal in the RuStore app.
Subscriptions screen can be opened with deeplink (see below).
startActivity(Intent(Intent.ACTION_VIEW, Uri.parse("rustore://profile/subscriptions")))
Below is the page with the list of deeplinks.
Q: Can I publish an app with RuStore SDK in Google Play, Huawei Store?
A: Yes.
Q: What is RuStore packageName?
A: ru.vk.store
.
Q: How to identify the store an app is installed from?
A: You can do it the following way.
val installerPackage = packageManager.getInstallerPackageName(applicationInfo.packageName)
this will return ru.vk.store
, however, the function is unstable.
- This works only for apps that were initially installed from RuStore. If an app was initially installed from Google Play or otherwise, then, the source would be the standard package installer.
- If the installation was done in the compatibility mode (as on some Xiaomi models), then, the source would be the built-in Xiaomi installer.
- If one deletes RuStore, the source will be deleted completely. Reinstalling RuStore will not return the installation source.
We recommend making a separate buildFlavor
for RuStore.
Q: Why are there timeout errors in payment methods? (PayLibBackendFailure$TimeoutError
)
A: RuStore SDK payment is unavailable outside Russia. An active VPN connection can lead to problems with payments.
Q: Is Java supported?
A: Yes. Kotlin is backward-compatible with Java, however, with some quirks.
For example, let’s take the object
entity from Kotlin, which is an analogue of the static class
in Java (see below).
RuStoreReviewManagerFactory.create(context)
Below is a call to RuStoreReviewManagerFactory
object
in Java.
RuStoreReviewManagerFactory.INSTANCE.create(getContext());
To learn more how to use Kotlin code in Java classes, please Calling Kotlin from Java.
Q: What types of purchases need confirmation?
A: Only CONSUMABLE purchases need confirmation.
Q: Are purchases that are not confirmed deleted automatically or do I have to delete them manually?
A: The purchase status will be changed to CANCELLED within 3 days, or if there is another attempt to make this purchase.
Q: What is consoleApplicationId
?
A: This is an application code from the RuStore Console (example: https://console.rustore.ru/apps/111111). Here: consoleApplicationId = 111111
.
Q: How to test payments during the development?
A: Our sandbox is available right after moderation.
Q: How to make subsequent purchases of consumable products?
A: A purchase needs to be confirmed so that the product could be purchased again.
Q: For which types of products is subscriptionToken
generated?
A: subscriptionToken
is generated for all types of products.
Q: In which circumstances the subscriptionToken
is null and how to avoid that?
A: subscriptionToken
is null only in case of system failures, for example: if something fails on the backend side. The nullable value is used only to prevent from crashes in case of problems with nullable values parsing.
Q: Can I save the AppUpdateInfo
object in a local variable in order to not request it again?
A: The AppUpdateInfo
object becomes invalid after a single use. Thus, every time you need to request a new one with the getAppUpdateInfo()
method.
Q: How many requests does it take for Review API to return RuStoreRequestLimitReached
?
A: The SDK screen can be called not earlier that 24 hours after the previous call. In general, we do not recommend displaying the review prompt to often - particularly, because it will damage user experience.
Q: How do I get the device push token?
A: You can review a log with the push token.
Q: Will your SDK work after RuStore is installed and then removed form a device? If yes, which ones?
A: Yes, PushSdk will work without RuStore.
Q: How do I check the APK signature?
A: Please, see section APK signature check, to learn how to check the APK signature.