Where to initialize BillingClient from Google Play Billing Library? - android

I’d like to use the Google Play Billing Library for in-app billing in my Android app. When the app launches, I’d like to initialize the BillingClient, start the connection, and retrieve some product data. The actual purchase would happen from a different activity (not the launch activity).
Should I make some kind of singleton billing manager that contains the BillingClient, so I can start it when the app launches and still use it in the other activity? Or is there a better approach?

There is an example provided by Google. In this example, they use additional BillingManager class which can be accessed from different places of your application but it isn't a singleton because it's not only about BillingClient you also have to have PurchasesUpdatedListener which is receiving updates from the BillingManager.
If you want to make BillingClient a singleton you can use BillingManager from the sample app and manage the list of BillingUpdatesListener by yourself.

You can try following approach:
mBillingManager = new BillingManager(this, getUpdateListener());
mBillingManager.startServiceConnection(new Runnable() {
#Override
public void run() {
// Do AnyThing Here
}
});

Related

Google Play Services: Account has no SCOPE_GAME_LITE permissions and cannot view Leaderboard

I followed the instructions on https://developers.google.com/games/services/android/signin and can successfully sign in and get data from an account (like .getEmail(), etc).
But when i try to show the leaderboard, i get the error:
java.lang.IllegalStateException: Games APIs requires https://www.googleapis.com/auth/games_lite function.
Games.getLeaderboardsClient(this, GoogleSignIn.getLastSignedInAccount(this))
.getLeaderboardIntent(getString(R.string.leaderboard_highscores))
.addOnSuccessListener(new OnSuccessListener<Intent>() {
#Override
public void onSuccess(Intent intent) {
startActivityForResult(intent, RC_LEADERBOARD_UI);
}
});
Indeed,
GoogleSignIn.hasPermissions(account, Games.SCOPE_GAMES_LITE));
returns false.
Everything in the Google Play Console should be set up correctly.
I also tried silentSignIn() without success.
What could be the issue here?
Ok, so i solved the issue...
Turns out i only had to wait for ~36h for all the changes to take effect.
This was even though the game console told me that everything was published and ready to use.
So don't get crazy and just wait.
Check Troubleshooting Issues in Your Android Game : Anonymous listeners
Do not use anonymous listeners. Anonymous listeners are unreliable
because the Play Games SDK maintains them as weak references, which
means that they might be reclaimed by the garbage collector before
they are invoked. Instead, you should implement the listener using a
persistent object such as the Activity.

how to cancel an in-app test purchase on android?

Until june 20th 2016 i was able to cancel test purchases done in my app.
Doing multiple in-app purchases (not consumable) from the same test account made it easy to develop and test the code without too much hazzle.
After 20th june 2016, the purchases did not show in my merchant account and
i was unable to do more than 1 purchase from my test account. All i got was the: "you already own this item" message.
I logged a request to the google developer support group and the answer was:
Beginning June 20, 2016, we changed test purchases for one-time in-app purchases (IAPs).
Previously, test purchases for one-time IAPs generated order IDs. Starting June 20, 2016, one-time IAPs do not generate official order IDs (if at all) and will not appear in the Merchant Center. This behavior already applies to subscription IAPs.
You can learn more about testing in-app billing in the Android Developers Help Center: https://developer.android.com/google/play/billing/billing_testing.html#testing-purchases
allright.. so i go to the mentioned link and theres a section there:
Canceling completed test purchases
which states:
Google Play accumulates completed test purchases for each user but does not pass them on to financial processing.
In some cases, you might want to manually cancel a test purchase to continue testing. To do so, open the app page in the Play Store. If the test purchase that you want to cancel is a subscription, you can also use the cancel() method of the Purchases.subscriptions API.
Important: The refund() and revoke() methods of the Purchases.subscriptions API don't support test purchases.
So I go to the app page in play store...and do what exactly? the webpage does not state what i am supposed to do there. anyone know?
it does say: you can also use the cancel() method of the Purchases.subscriptions API.
which indicates that using the cancel() method is not the only method.
How to solve this without adding additional code in my app?
I went into the main Google Play Console page and clicked on Order Management. Under that I was able to select all test purchases and Refund them. I'm the primary developer of the app so I have access. If you are a tester you'd probably have to contact the support team and request that they refund your order.
All managed in-app products are consumable.
as stated in the docs.
That means that you can consume an owned item instead of cancelling the purchase and buy it all over again.
I suggest querying the inventory at the app launch time:
mIabHelper.queryInventoryAsync(this);
You can then consume the owned item in the callback:
#Override
public void onQueryInventoryFinished(IabResult result, Inventory inventory) {
Purchase purchase = inventory.getPurchase(MY_SKU);
boolean isBought = (purchase != null && verifyDeveloperPayload(purchase));
if (isBought) {
mIabHelper.consumeAsync(purchase, new OnConsumeFinishedListener() {
#Override
public void onConsumeFinished(Purchase purchase, IabResult result) {
//Clear the purchase info from persistent storage
}
});
}
}
This is OK for testing the IAB flow but make sure to remove this code from the release version.
On Play Console, go to Developer Account -> Account Details, set the license testers (you are one by default)
Purchase items
Go to Order Management, choose those test orders, select: refund, but DON'T FORGET to check REVOKE when you are refunding. (I forgot to revoke, and now can't find a way to take them back)
Anyway, another test account will do.
I found a solution which isn't very convenient, but works. It seems like you can consume uncomsumable products and that way you can buy them again. I'm working with phonegap so I only have example code for the cordova-plugin-purchase plugin:
store.when("your.product.id").updated(product => {
if(product.owned) {
var transaction = product.transaction;
product.transaction = null;
store.inappbilling.consumePurchase(
function() { // success
alert("consume success");
},
function(err, code) { // error
alert("consume error " + err)
},
product.id,
transaction.id
);
}
});
The updated callback gets called when you call store.refresh() or buy the product. So depending on your use case you'd want to implement an additional method of checking when to consume the product.
I have no experience with the native Android in-app payments, but obviously you will be able to consume the products there as well.
Edit: Sorry, I just read that you didn't want to include additional code in your project. I don't think that's possible at the moment, but would like to keep my answer here because it might help other people trying to test in-app payments.
What worked for me was a combination of both:
Go to order management and refund
clear cache/data in Play Store app (as well as your app in you placed some shared prefs).
Also, in case you get an item already owned status, you can consume the purchase using the purchase token and calling billingClient.consumeAsync().
Didn't find a solution for this.
My workaround is simply remove the current test user from the test users list, make a real purchase, then cancel it using the merchant console.
The queryPurchaseHistoryAsync method still finds test orders I've made over the last year, despite having long ago consumed, refunded, and revoked them. One precaution I've found helpful is clearing the data in the Google Play Store app (settings/apps/google play store/storage/clear data). queryPurchaseHistoryAsync pulls obsolete purchase data from here, although only the non-networking (and completely unreliable I've found) queryPurchases is supposed to do this. You may have to add additional code to your app after all, but it doesn't have to be much.
With the dropping of support for Trivial Drive 2 (the link in the docs takes you to a '404 page does not exist' error, the github files are archived, and updating to billing:2.1.0 will give you a vending import compile error in the IabHelper class), answers to this popular question involving IabHelper might be considered obsolete. Billing is a lot simpler now if you follow the basic code pieces in the docs starting here https://developer.android.com/google/play/billing/billing_overview with no messy helper classes. One persistent issue is a 'Both methods have same erasure, yet neither overides the other' method clash error you may run into with this implementation, see my solution here 'Both methods have same erasure, yet neither overides the other' method clash error in SkuDetailsResponseListener().
Once you have the newest billing code implemented, you can create a hidden trigger in your production app to call queryPurchaseHistoryAsync to get a purchaseHistoryRecordList. Then call consumeAsync for each item in this list. Here is the barebones code to consume all test orders, allowing multiple tests of your nonconsumables:
billingClient.queryPurchaseHistoryAsync(BillingClient.SkuType.INAPP,
new PurchaseHistoryResponseListener() {
#Override
public void onPurchaseHistoryResponse(BillingResult billingResult,
List<PurchaseHistoryRecord> purchaseHistoryRecordList){
if (billingResult.getResponseCode() == BillingClient.BillingResponseCode.OK
&& purchaseHistoryRecordList != null) {
for (PurchaseHistoryRecord purchaserecord : purchaseHistoryRecordList) {
if(purchaserecord!=null){
ConsumeParams consumeParams =
ConsumeParams.newBuilder()
.setPurchaseToken(purchaserecord.getPurchaseToken())
.setDeveloperPayload(purchaserecord.getDeveloperPayload())
.build();
billingClient.consumeAsync(consumeParams, consumelistener);
}}}}});
For people using a way based on the new TrivialDriveKotlin, consumable products are consumed during the installation of the app in the method
handleConsumablePurchasesAsync
If your purchase is not consumable, you can make it consumable by adding the corresponding sku into CONSUMABLE_SKUS in the GameSku object. Exemple:
val CONSUMABLE_SKUS = listOf(GAS, PREMIUM_CAR)
Then uninstall your app from your device and install it again, and your non consumable purchase is available again. Fast and simply.
Of course, don't forget to remove your

Should we create instance of EasyTracker multime times when trying to send logs to Google Analytics dashboard

I am using Google Analytics in android project. For this wherever I'm sending analytics I'm creating object of EasyTracker class.
Suppose user is on First Activity then I'm creating the object of EasyTracker in onCreate so when user navigate to second activity then again I'm creating object of EasyTracker in onCreate of second activity.
Should we create object of EasyTracker once only and use it same in entire application or this does not matter. I guess that by creating two object of EasyTracker Google Analytics is assuming that there are two real time users but exact is only one.
EasyTracker easyTracker = EasyTracker.getInstance(ActivityMain.this);
Thanks in advance.
Look at sample:
#Override
public void onStart() {
super.onStart();
... // The rest of your onStart() code.
EasyTracker.getInstance(this).activityStart(this); // Add this method.
}
#Override
public void onStop() {
super.onStop();
... // The rest of your onStop() code.
EasyTracker.getInstance(this).activityStop(this); // Add this method.
}
https://developers.google.com/analytics/devguides/collection/android/v3/
It seems that EasyTracker is singletone and you should call getInstance every time.
You should consider switching to a newer v4 version of the Google Analytics SDK for Android. v4 of the API support automatic activity reporting - Tracker.enableAutoActivityTracking. Once you enable automatic tracking it does the screen reporting for you. Easy tracker is v2/v3 of the API and doesn't support many new features added to Google Analytics like demographics reporting. Google only maintains the latest version of the SDK so v2/v3 might not work that well on newer versions of Android.

Android Turnbased multiplayer detected incorrect implementation Google Play Game Services alert

I have published an Android app using the Google Play Game service and have been informed of an alert that says it has "Detected incorrect implementation". Investigating what this means I found that...
This game has implemented invitations but doesn't allow users to join a match from an invitation. This approach is discouraged because it could result in a poor user experience.
Since I based this game on the sample project (TypeANumber) I am unsure what I need to do to comply with this alert. What should I be looking for in the code that would cause this alert, since I have invited and played against my friends quite happily and not experienced such an issue.
I have encountered (and now cleared) this alert. I suggest the following:
If you have implemented the OnInvitationReceivedListener i.e.
class myClass extends Fragment implements OnInvitationReceivedListener, ...
and do not want to handle this yourself, then simply remove OnInvitationReceivedListener from your
implements clause. This is what I did, and it cleared the alert.
Alternatively, if you do want to handle the invitation, then as well as having the OnInvitationReceivedListener in the implements clause you also need to register the invitation listener at run time i.e.
Games.Invitations.registerInvitationListener(getApiClient(), this)
and provide the listener code i.e.
public void onInvitationReceived(Invitation invitation) {
...
}

Android - how to check if in app purchase has already been done?

How do i check if a in app purchase has been done before?
So that my user doesnt need to repurchase the in app purchase upon uninstalling and reinstalling the app?
I have set my in app item to managable in the android market publish page.
i have read about RESTORE_TRANSACTION but I do not know what i need to look for inside this response and also how to test this.
Any help would be greatly appreaciated.
You need to restore the transactions, using the RESTORE_TRANSACTION flag you specified above. You should only do this once, when the application starts for the first time or if the user clears the data.
I would advice to make this process simpler for yourself, you looking into the AndroidBillingLibrary, which allows you to interface with the Android In App Billing in a much simpler manner.
Here is a snippet of how the transactions are restored:
private void restoreTransactions() {
if (!mBillingObserver.isTransactionsRestored()) {
BillingController.restoreTransactions(this);
Toast.makeText(this, R.string.restoring_transactions, Toast.LENGTH_LONG).show();
}
}

Categories

Resources