Android billing: startConnection failing randomly - android

We have an app in production that most of the time works fine when users are purchasing a subscription. But we do get some reports of users not being able to get to the purchase screen.
I have identified that these users always get BillingResponseCode.SERVICE_DISCONNECTED when running this code
billingClient.startConnection(object : BillingClientStateListener {
override fun onBillingSetupFinished(billingResult: BillingResult) {
if (billingResult.responseCode == BillingResponseCode.OK) {
oncomplete()
}
else {
onError()
}
}
override fun onBillingServiceDisconnected() {
retry()
}
}
Rerunning the startConnection method does not help and thus these users are stuck. If they try it later(hours or days) it might work just fine again.
We are running version 4.0 of the billing library.
Does anyone have an idea of why this happens?

Related

JobCancellationException with in-app updates

I've noticed that some of the users have issues to use flexible in-app update, the JobCancellationException: Job was cancelled is thrown with incomprehensible stack trace:
at dalvik.system.VMStack.getThreadStackTrace(VMStack.java)
at java.lang.Thread.getStackTrace(Thread.java:1538)
at java.lang.ThreadGroup.uncaughtException(ThreadGroup.java:1068)
at java.lang.ThreadGroup.uncaughtException(ThreadGroup.java:1063)
at java.lang.Thread.dispatchUncaughtException(Thread.java:1955)
Unfortunately, I don't which part of the code is causing the issue. This is the only coroutine related code, staying in MyViewModel:
init {
viewModelScope.launch {
try {
appUpdateManager.requestUpdateFlow().collect { appUpdateResult ->
// Do something with result.
}
} catch (e: InstallException) {
// Do something with an error.
}
}
}
fun requestUpdate(fragment: Fragment) {
viewModelScope.launch {
try {
val appUpdateInfo = appUpdateManager.requestAppUpdateInfo()
appUpdateManager.startUpdateFlowForResult(
appUpdateInfo,
AppUpdateType.FLEXIBLE,
fragment,
REQUEST_CODE
)
} catch (e: IntentSender.SendIntentException) {
}
}
}
I suspect that code inside requestUpdateFlow() is calling offer while the coroutine job is already cancelled and I can't see the exact stacktrace, because Play Core library is obfuscated?
I'm using following versions of the libraries:
"com.google.android.play:core:1.7.2"
"com.google.android.play:core-ktx:1.7.0"
JobCancellationException: Job was cancelled is thrown in almost case is job in coroutine scope is cancelled.
Example: User go to a screen a in which call api to get something. But user press back to close this screen while api not complete. Thus, when receive response, job cancelled before -> exception.
To more handle JobCancellationException you can using suspendCancellableCoroutine.
More detail : https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/suspend-cancellable-coroutine.html

Android billing library V3.0.0 does not work

It does not work. As simple as that. I used default code given in google docs.
private fun initBilling() {
val purchasesUpdatedListener = PurchasesUpdatedListener { billingResult, purchase ->
Log.d("Billing", billingResult.debugMessage)
}
val billingClient = BillingClient.newBuilder(this#Home)
.setListener(purchasesUpdatedListener)
.enablePendingPurchases()
.build()
billingClient.startConnection(object : BillingClientStateListener {
override fun onBillingSetupFinished(billingResult: BillingResult) {
Log.d("Billing", billingResult.debugMessage
?: "billing setup finished with response code ${billingResult.responseCode}")
if (billingResult.responseCode == BillingClient.BillingResponseCode.OK) {
// The BillingClient is ready. You can query purchases here.
CoroutineScope(Dispatchers.IO).launch {
querySkuDetails(billingClient)
}
}
}
override fun onBillingServiceDisconnected() {
// Try to restart the connection on the next request to
// Google Play by calling the startConnection() method.
Log.d("Billing", "disconnected")
}
})
}
None of the Logs that I used were printed and no errors were showing. Start connection just does not trigger any methods from BillingClientStateListener.
There is an unknown issue with android billing library v3.0.0. Just switching to 2.1.0 helped.

Android: AWS Amplify User State is not getting update

I have just started learning AWS Amplify and I am integrating it to my android project to authenticate users. I have successfully logged-in but UserState is still SIGNED_OUT.
AWSMobileClient.getInstance().signIn(userName, password, null, callback)
Callback Code snippet
fun fetchAuthenticationCallBack(): Callback<SignInResult> {
return object : Callback<SignInResult> {
override fun onResult(result: SignInResult?) {
when (result?.signInState) {
SignInState.DONE -> {
// AWSMobileClient.getInstance().confirmSignIn()
Log.d(TAG, "LOGIN SUCCESS ${AWSMobileClient.getInstance().tokens.accessToken}")
}
SignInState.NEW_PASSWORD_REQUIRED -> {
Log.d(TAG, "NEW PASSWORD CHALLENGE")
}
else -> {
// Unsupported sign-in confirmation:
}
}
}
override fun onError(e: java.lang.Exception?) {
TODO("Not yet implemented")
}
}
}
I want to get the accessToken but it gives me Exception
Token does not support retrieving while user is SIGN_OUT
Is there anything that I am missing in the authentication part?
If anyone will face this issue in the future.
Kindly check your awsconfiguration.json file there is something went wrong. In my case CognitoIdentity credentials were wrong. I have just fixed the awsconfiguration.json file everything is working as expected

queryPurchases() returns an empty list

I have implemented the Billing library in order to have in-app products in my app. I can make a successful purchase and everything works fine. If I try to make a purchase again, I get the response "Product already owned" which shows that the purchase is fine. I am using as productID the test id: "android.test.purchased"
Moreover, in the Main's Activity onResume() method, I call the queryPurchases() method in order to restore the product in case the user deletes the app and re-installs it. However, this method returns an empty purchases list although the response code is OK.
This is the way I am using the method:
private fun startServiceConnectionIfNeeded(executeOnSuccess: Runnable?) {
if (mBillingClient.isReady) {
executeOnSuccess?.run()
} else {
mBillingClient.startConnection(object : BillingClientStateListener {
override fun onBillingSetupFinished(#BillingClient.BillingResponse billingResponse: Int) {
if (billingResponse == BillingClient.BillingResponse.OK) {
Log.i(TAG, "onBillingSetupFinished() response: $billingResponse")
executeOnSuccess?.run()
} else {
Log.w(TAG, "onBillingSetupFinished() error code: $billingResponse")
}
}
override fun onBillingServiceDisconnected() {
Log.w(TAG, "onBillingServiceDisconnected()")
}
})
}
}
// I call this method in Main's onResume()
fun updateBillingSharedPreferencesKey() {
val executeOnConnectedService = Runnable {
val purchasesResult = mBillingClient.queryPurchases(BillingClient.SkuType.INAPP)
val purchasesList = purchasesResult?.purchasesList
purchasesList?.let {
// this list is always empty, although I have a valid product
for (purchase in it) {
// I never enter this loop to handle the product functionality
Log.d(TAG, "purchase.sku = ${purchase?.sku}")
}
}
}
startServiceConnectionIfNeeded(executeOnConnectedService)
}
Am I doing something wrong? The service connection and the response code is ok.
How should I call the queryPurchases() method to get my valid in-app product?

Not receiving SkuDetails List

I'm trying to test in-app subscriptions for an app I'm working on. The problem is that the SkuDetails list comes empty. I've read in the documentation that the app must first be published to alpha before the subscription stuff can be tested.
As I understand it, after the app is published to alpha I can test a build with the same version on the device and can debug and all that. I don't need to download the release build from alpha.
One of the possible issues is that the app seems to need Google approval before being published to alpha (it has the status of Pending Publication). I don't understand the need for approval as it is just an alpha build.
For now I'm just trying to get the SkuDetails list. In GooglePlay Console I have setup a single subscription and set it to Active. Code wise I have this function:
fun setupBilling(context: Context, callback:
(result: BillingResult,skuDetailsList: List<SkuDetails>) -> Unit) {
billingClient = BillingClient.newBuilder(context)
.enablePendingPurchases()
.setListener(this).build()
billingClient.startConnection(object : BillingClientStateListener {
override fun onBillingSetupFinished(billingResult: BillingResult) {
if (billingResult.responseCode == BillingResponseCode.OK) {
querySkuDetails(billingClient, callback)
}
}
override fun onBillingServiceDisconnected() {
// Try to restart the connection on the next request to
// Google Play by calling the startConnection() method.
}
})
}
The querySkuDetails function looks like:
private fun querySkuDetails(client: BillingClient,
callback: (result: BillingResult,
skuDetailsList: List<SkuDetails>) -> Unit) {
val params = SkuDetailsParams.newBuilder()
params.setSkusList(skuList).setType(BillingClient.SkuType.SUBS)
client.querySkuDetailsAsync(params.build()) {
billingResult, skuDetailsList ->
callback(billingResult,skuDetailsList)
val msg = billingResult.debugMessage
Log.d(TAG, "List Size: ${skuDetailsList.size}")
Log.d(TAG, msg)
}
}
In the above code, skuList is a list of String with a single element that is my subscription identifier from the Play Console.
There is no debugMessage and the list size is always 0 even though it should be 1.
Any help is appreciated.
Thanks!
Razvan
After 4 days since I uploaded the Alpha version on Google Play, Google approved it and now everything works. So the only thing that I had to do was to wait for Google to approve the app (even if it was just an alpha version).

Categories

Resources