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

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();
}
}

Related

Play Core In-App Review API not showing the Review Activity

I'm trying to utilize the Review API (Play Core library 1.8.0) from Google which was just released yesterday.
See https://developer.android.com/guide/playcore/in-app-review
I followed the troubleshooting section carefully, I made sure the app is downloaded from the internal testing track, my account does not have a review on the app, the app is in the library of that user etc.. I even tried with a completely new account, but every time the com.google.android.finsky.inappreviewdialog.InAppReviewActivity is shown only to immediately disappear.
I'm calling the following code from the onResume() method of my activity:
reviewManager = ReviewManagerFactory.create(AlarmClock.this);
Logger.logInfo("Rating: requestReviewFlow() ");
reviewManager.requestReviewFlow().addOnSuccessListener(new OnSuccessListener<ReviewInfo>() {
#Override
public void onSuccess(ReviewInfo result) {
Logger.logInfo("Rating: launchReviewFlow() ");
reviewManager.launchReviewFlow(AlarmClock.this, result).addOnSuccessListener(new OnSuccessListener<Void>() {
#Override
public void onSuccess(Void result) {
Logger.logInfo("Rating: launchReviewFlow() success ");
}
});
}
});
Both listeners return success.
Here is the log output:
2020-08-06 16:01:29.317 29618-29618/? I/MyApp: [06Aug 16:01:29.317, main]: Rating: requestReviewFlow()
2020-08-06 16:01:29.318 29618-29618/? I/PlayCore: UID: [10409] PID: [29618] ReviewService : requestInAppReview (com.mypackage)
2020-08-06 16:01:29.320 29618-29774/? I/PlayCore: UID: [10409] PID: [29618] ReviewService : Initiate binding to the service.
2020-08-06 16:01:30.081 29618-29618/? I/PlayCore: UID: [10409] PID: [29618] ReviewService : ServiceConnectionImpl.onServiceConnected(ComponentInfo{com.android.vending/com.google.android.finsky.inappreviewservice.InAppReviewService})
***2020-08-06 16:01:30.082 29618-29774/? I/PlayCore: UID: [10409] PID: [29618] ReviewService : linkToDeath***
2020-08-06 16:01:30.355 29618-29637/? I/PlayCore: UID: [10409] PID: [29618] OnRequestInstallCallback : onGetLaunchReviewFlowInfo
2020-08-06 16:01:30.355 29618-29774/? I/PlayCore: UID: [10409] PID: [29618] ReviewService : Unbind from service.
2020-08-06 17:02:21.590 7478-7478/? I/MyApp: [06Aug 17:02:21.590, main]: Rating: launchReviewFlow()
2020-08-06 17:02:21.630 1511-4316/? I/ActivityTaskManager: START u0 {cmp=com.android.vending/com.google.android.finsky.inappreviewdialog.InAppReviewActivity (has extras)} from uid 10122
2020-08-06 17:02:21.750 7478-7478/? I/MyApp: [06Aug 17:02:21.750, main]: Rating: launchReviewFlow() success
Anyone had success to make this working? Any tips. Big thanks!
Okay, I had exactly the same problem as described by the OP and as is listed on the issue tracker here: https://issuetracker.google.com/issues/167352813 and has still not been resolved as yet by GoogleDev.
Same UI manifestation(s), same log entries (incidentally, the log entries are the same when it works though, complete with the entry that says “ReviewService : linkToDeath”, but let’s not worry about that eh?)
The key thing, you'll no-doubt want to know though, to avoid too much suspense, is that IT WORKS. The in-app review API works! No need for me to repeat the block of code for calling the review flow, it is pretty much exactly the same as in the docs, similar to what the OP has listed, and several others have kindly repeated.
Took me a while, but I got to the bottom of it as follows, in a nutshell:
Your device needs to have the latest Google Play system update
Irrespective of whether your app is published on the Play Store YOU ABSOLUTELY NEED TO DO YOUR TESTING VIA INTERNAL APP TESTING or SHARING (I only did “Internal App Testing”, but I expect the same applies)
To debug your code with Android Studio, you need to have installed your Internal App Testing version on your device AND RUN THE DEBUGGER SUCCESSFULLY WITH YOUR IAT VERSION STILL INSTALLED ON THE DEVICE AT LEAST ONCE
Once you are up and running, when the review dialog pops up, you have to note that, if you submit a review, then you have utilised all your quota. When you try and launch the review flow again it looks like the “problem” has returned. You get “successful” launch but nothing shows. If you have submitted a review (and this is why it absolutely needs to be in IAT), then it is only a “private review” (not seen publicly on your app page), and you need to DELETE THE REVIEW TO GET THE POP UP TO SHOW AGAIN.
You can select “Not Now” instead of "Submit" ad infinitum (well, I tried about two-dozen times) and the pop-up dialog will launch each time you (re)call the flow.
So, step-by-step fix:
Prepare your device by uninstalling your app, then ensure you have the latest Google Play Store update. On my Sony Xperia X1 this is Settings->About Phone->Android version->Google Play system update.
Irrespective of whether the above restarted your device, turn your device off and then back on again (don’t restart - off then on i.e. cold boot).
Now go into Settings->Apps & notifications->Google Play->Storage & Cache, then do both CLEAR CACHE and CLEAR STORAGE. (This should not affect any of your installed apps).
Create a signed release for IAT based on your In-App review code base. You have to do this even if you have a release in production.
Now install your IAT RELEASE on your device - the words, "(Internal Beta)" or words to that effect, should be appended to your app name if you are downloading from the right location (i.e. IAT), (do not run it, just install)
In Android studio Clean, Rebuild and Debug, your app on the device with the IAT version installed. If you get a message saying "The device already has an application with the same package but a different signature." DON'T CLICK OK TO UNINSTALL YOUR IAT VERSION Follow the instructions here: Android: Error - App has same packaged different signature. The accepted answer is the correct one. If you have to do this, please note you should do a Clean and Rebuild->Debug again.
Hopefully, now all should be okay. Once you have done the above steps successfully, you can actually "clean" uninstall the app from the device on subsequent debugging sessions, and it will still work.
To test, and to delete a review note the following. When you submit a review, you will be able to see it in Google Play Console (not under "Reviews", incidentally but) under "Testing Feedback". Also you cannot delete your review under "Testing Feedback" it seems. You need to delete it from your IAT download page on the device. On there, under the heading Your private feedback, select the right-angled ellipsis thingy to the right of your review and simply "Delete".
Your pop-up will now show every time until you submit another review. Voila!
I have raised a issue on google issue tracker regarding this. I also have the same issue.
For more info check this my issue tracking url: https://issuetracker.google.com/issues/167352813
I also saw the same problem, my request review flow works, then the launch review flow works, but nothing displays (I do notice the small line at the center of the bottom of the screen appears briefly, and my audio cuts out briefly as the app is paused and then resumed but no review flow appeared).
I was able to get it to work by adding a user to my device that was not in my list of License Testers (Google developer console) and had not reviewed my app previously. I was able to display the rating popup once, I cancelled the operation so that I could test it again, but it would not reappear afterwards. It appears to be a one shot thing and they are aggressively guarding against annoying the user with review popups.
This feature doesn't seem useful for my case, I have a button on the settings screen to rate my app. Since I have no way of knowing what happened, I can't thank the user, I can't disable the button or display an "you already rated this thank you" message, and the button just appears to do nothing so it looks like a bug. I guess the intended use is to ask the user during gameplay, and if they cancel the dialog accidentally then it's just too bad for you.
Ideally Google should allow License Testing users to display this popup more than once for testing purposes.
I just want to share the code that is working reliably today (2020-09-03). It was essentially copied from the official document
ReviewManager manager = ReviewManagerFactory.create(activity);
Task<ReviewInfo> request = manager.requestReviewFlow();
request.addOnCompleteListener(task -> {
try {
if (task.isSuccessful()) {
// We can get the ReviewInfo object
ReviewInfo reviewInfo = task.getResult();
Task<Void> flow = manager.launchReviewFlow(activity, reviewInfo);
flow.addOnCompleteListener(task2 -> {
// The flow has finished. The API does not indicate whether the user
// reviewed or not, or even whether the review dialog was shown. Thus, no
// matter the result, we continue our app flow.
utility.logMessageAsync(activity, "In-app review returned.");
});
} else {
// There was some problem, continue regardless of the result.
goToAppPage(activity);
}
} catch (Exception ex) {
utility.logExceptionAsync(activity, "Exception from openReview():", ex);
}
});
It was tested with internal app sharing on a Android 10. It never failed to show the review dialog.
I had the same problem and I solved with the next steps:
Adding my APK file to internal testing channel
Adding a tester user with a gmail account ex: email#gmail.com. GSuite mails don't work
With the tester mail, accept the tester privilege
With a physical device signed with the tester user email, go to Play Store and download the app
It works!!
Note: If App is not published yet, you could use Google Console App Sharing
Try uploading your app to Internal App Sharing
I have found that with the exact same apk uploaded to Internal Testing versus Internal App Sharing, the latter is more reliable in displaying the In-App Review Flow every time I try testing it.
You would need to enable Internal app sharing in the Play Store to be able to install your app from the link provided by uploading your apk.
Basically go to the Play Store, go to Settings, scroll down to Play Store version and tap it a bunch of times to "Become a developer", then enable Internal app sharing.
For all the users that needs a working JAVA code, please find my code below:
ReviewInfo reviewInfo;
ReviewManager manager;
OnCreate
manager = ReviewManagerFactory.create(this);
private void Review(){
manager.requestReviewFlow().addOnCompleteListener(new OnCompleteListener<ReviewInfo>() {
#Override
public void onComplete(#NonNull Task<ReviewInfo> task) {
if(task.isSuccessful()){
reviewInfo = task.getResult();
manager.launchReviewFlow(MainActivity.this, reviewInfo).addOnFailureListener(new OnFailureListener() {
#Override
public void onFailure(Exception e) {
Toast.makeText(MainActivity.this, "Rating Failed", Toast.LENGTH_SHORT).show();
}
}).addOnCompleteListener(new OnCompleteListener<Void>() {
#Override
public void onComplete(#NonNull Task<Void> task) {
Toast.makeText(MainActivity.this, "Review Completed, Thank You!", Toast.LENGTH_SHORT).show();
}
});
}
}
}).addOnFailureListener(new OnFailureListener() {
#Override
public void onFailure(Exception e) {
Toast.makeText(MainActivity.this, "In-App Request Failed", Toast.LENGTH_SHORT).show();
}
});
}
Make sure the below is implemented:
implementation 'com.google.android.play:core:1.8.0'
And please also note, that the dialog will only display if your app is in production, alpha or internal testing on the Google Play Console Account.
I had same issue, I've followed below steps then working fine
If you mark stars and submit, then need to remove your review from
play store.
Clear data for Play Store.
My working code:
private fun askForReview() {
val manager = ReviewManagerFactory.create(this)
manager.requestReviewFlow().addOnCompleteListener { request ->
if (request.isSuccessful) {
val reviewInfo = request.result
manager.launchReviewFlow(this, reviewInfo).addOnFailureListener {
logWarning("In-app review request failed, reason=$it")
}.addOnCompleteListener { _ ->
logInfo("In-app review finished")
}
} else {
logWarning("In-app review request failed, reason=${request.exception}")
}
}
}
Tested on an app from Internal Test track (there is no quota there).
The documentation says
To provide a great user experience, Google Play enforces a quota on
how often a user can be shown the review dialog. Because of this,
calling a launchReviewFlow method might not always display a dialog.
For example, you should not have a call-to-action option (such as a
button) to trigger a review as a user might have already hit their
quota and the flow won’t be shown, presenting a broken experience to
the user.
So you don't expect it to show the dialog every time and also there's no way to know if the dialog is shown or not nor the user has reviewed your app or not either
I had exactly the same problem, the dialog never appeared to me ...
But even so, I left it implemented in the application and posted it on the Play store.
Then I downloaded and tested the version and everything works perfectly.
Most of the cases are covered in other answers. I want to highlight few more troubleshooting Steps .
Make sure the user account is not protected (like some enterprise accounts) use some personnel G mail ID to test.
Make Sure the version of beta app is greater then the currently Live application
if its not then it will not show up the review dialogue.
In MY case, yes, this will not work if the account that’s being used already left a review.
HOWEVER, deleting the review from the Play Store doesn’t always work. Something lingers.
So, unless you want to be sad, CLEAR THE PLAY STORE APP’S STORAGE EVERY TIME YOU DELETE THE REVIEW THAT’S LEFT. You do not need to also clear the cache as well as others have suggested (clearing the storage will also do this), but clearing the Play Store app’s cache was not enough. Once I did this, I could consistently test this ad nauseum.
Good luck. What a mess this is.
Documentation says that it won't be shown every time you request it since it has quota restrictions:
https://developer.android.com/guide/playcore/in-app-review#quotas
I just included it in my project and it showed the dialog only one time. It is a little inconvenient since we don't have any controls over it.
Also, I noticed that if you try to show the dialog again and again, navigation bar starts blinking (like it wants to show the dialog but it gets dismissed).
My problem was solved by typecasting the context and activity to the required form i.e application context and activity . Although it seems illogical, nothing else worked for me
I joined the beta in the store and it showed. But just show once time.
Just to be clear you are not using com.mypackage right?
2020-08-06 16:01:29.318 29618-29618/? I/PlayCore: UID: [10409] PID: [29618] ReviewService : requestInAppReview (com.mypackage)
Ensure that the appId used is the one that it's "owned" (aka installed by) by the selected account in the Play Store in the device.
I believe the test guide (https://developer.android.com/guide/playcore/in-app-review/test) is clear in terms of how to test it given the different requirements.
My tips:
Use only one account in the device
Ensure that account has installed the app (appears in the app & games > Library section in Play Store)
The account is a GMAIL one, not a GSuit
You can review with the account if you go to the app play listing page.
The account has not reviewed
If you intend to use the Internal Test Track ensure the account has joined the test track.
When switching between different accounts and testing things out, sometimes might be helpful to "Clear Data" from the Play Store app.
Try all the above with different account
PS: You could test also the Internal App Sharing.
Just discovered that the app must be approved from google (i.e. not having the temporary name)
The code is correct no issue
we can follow a few steps
app upload following URL https://play.google.com/console/u/0/internal-app-sharing/
setup google play console your project setup->inter app sharing-> anyone can download select the option -> to save
3 check your mobile internal app sharing to play store app
I know this is an old thread but none of the steps for the solutions provided worked for me. They are all great advice and should be followed. However, if you also can't get the in-app review UI to pop up, you might want to try what I did. (I'm sure there is probably a key step in there that is the actual solution so all these steps may not be necessary.)
Ultimately, the issue was that I initially installed my app using a gmail suite email (same one I used to deploy the app if that makes a difference) and the app remained associated with that user even after switching to other users on my phone.
Bad user is active in Google Play app
Uninstall the app (duh)
Go to bad user's library and remove the app
Stop and delete data/cache for Play Store app
(At this point I removed/re-added my good gmail user account in android settings but probably not necessary)
Start and switch to good gmail account in Play Store app
(If you search for the app, you should see a little note under the name saying the app is associated with the bad user account. This means it will not work right. Don't install it yet!)
This is the important part!
Start Chrome browser, and login with good gmail account
Go to email and CLICK ON THE LINK TO INSTALL THE APP FROM YOUR INVITE to test it (notice that was in all caps so must be important)
The app should now be associated on this device with the good account and you should see the in-app review pop-up UI
For anyone still having this problem:
I used applicationContext and now it is working and displaying just fine.
For some reason, the context and activity don't work, only applicationContext.
Please test using FakeReviewManager :)
ReviewManager manager = new FakeReviewManager(context);
https://developer.android.com/guide/playcore/in-app-review/test

working on an Android Game, stuck at In app purchase programming

I am working on an Android Game. I got stuck at In app purchase programming.
I have decided to use Soomla Unity IAP plugin.
I tried their sample program of muffins, that worked well.
But I did not get idea how would I know if some one purchased coins(Or any good) from my game.
I have seen some videos on youtube, I have gone through git hub page of SOOMLA but didn't find anything which can clear my doubts.
Please help me out guys Or refer any worthy material you know.
Thank you !!
Your question isn't specific enough so I'll try to address several ways to go:
First, assuming you are selling coins for real money (market purchases), you want to use SOOMLA's event system to handle events when they're dispatched. A common event to register a handler for is OnMarketPurchase in which you will get notified when users purchase things with Google Play, Apple App Store, or Amazon, depending on your platform:
StoreEvents.OnMarketPurchase += onMarketPurchase;
public void onMarketPurchase(PurchasableVirtualItem pvi, string payload,
Dictionary<string, string> extra) {
// pvi - the PurchasableVirtualItem that was just purchased
// payload - a text that you can give when you initiate the purchase operation and
// you want to receive back upon completion
// extra - contains platform specific information about the market purchase
// Android: The "extra" dictionary will contain "orderId" and "purchaseToken"
// iOS: The "extra" dictionary will contain "receipt" and "token"
// ... your game specific implementation here ...
}
Second, you can use the StoreInventory class to query a user's inventory and thus know his \ her balances and what they've purchased:
StoreInventory.GetItemBalance("currency_coins");
Third - the method SoomlaStore.RefreshInventory (which runs by default on Android builds, but not iOS) should all also restore the user's previous transactions for lifetime goods, in which you can also handle triggered events, so that's another way of telling if a user has previously purchased something ("Remove Ads" for example).

How to protect Google In-App Billing v3 from code hacking?

Google provides a convenient API to implement "in-app purchase" features on an Android app.
Along with these docs, there is also a dedicated chapter regarding the security level of this system and the good ways to design it.
The web is full of articles about this step, from public key protection to remote server validation, but I really can't understand why all of these techniques should work when the main problem is, simply, code hacking.
Maybe there is a better term to explain it, but let me do a quick example. The basic idea of my application is that, at certain points, the user can't proceed unless he has purchased an item.
Something like:
public void accessTheVeryCoolFeature() {
boolean haveIt = checkIfPurchased("verycoolfeature");
if (haveIt) {
// YEAH! let's open this very cool feature I paid 200 bucks for
}
else {
// ok... where is my wallet?
boolean purchased = startPurchaseFlow("verycoolfeature");
if (purchased) {
// my wallet is now empty but happy
}
}
}
Following the previous guidelines, the developer can protect his app during the purchase process, letting the startPurchaseFlow method to query a remote, trusted, server that validates the receipt.
Purchases done using a "fake marketplace" should be avoided by this.
Another method is to protect the unlocked content by obfuscating the code. This is really simple with tools like ProGuard and should make the life of an "hacker" a bit harder.
Now, I tried to act the part of an hacker that want to read my code, especially the billing phase.
It took me like 1 minute to spot the code I wrote in the previous example. Now the best part: what if I edit the (obfuscated) source code to do this?
public void atvf() {
boolean hi = cip("verycoolfeature");
hi = true; // <------------------------ AHAH!
if (hi) {
// YEAH! let's open this very cool feature for free
}
// ...
}
All the good words about remote verification and code obfuscation are totally gone. So why spend hours on trying to implement them when the very first problem is in a boolean value?
Am I missing something?
Unless your app is heavily dependent on its functionality being in a server - as in each functionality stays on the server and the app is just a client tool to call those server APIs, there is nothing you can do. If indeed it's a server-based app - you can check each incoming request (e.g. the app can send a one time session hash) if a valid transaction exists for it and is paid. If not, deny the request.
The app's code is running on the client's phone. If the hacker gains access to that code and is free to modify it to override any billing validations - there is nothing you can do. You should make sure he doesn't gain access to that source code in the first place.

in-app billing basics for beginner

some might remember me from previous questions. I'm building an app for Android and it's going well. Most of the functions I wanted work great. I learned the basics by myself (and with the help of a few generous people here on StackOverflow!) but I still consider myself a beginner (today's question will show you how much of a beginner I am!).
My app is a dynamic map that shows the history of a country at a specific point in time. On Google Play, the user can download for free the base app (mostly empty), then he can buy packs (France, USA, UK, etc.) with in-app billing. That's where I am stuck.
I've bought the Milkman AndroidIAB ANE and read carefully the documentation (this one). I've managed to add the ANE to my library and update my application manifest. I've modified the example file to add my public key and the IDs for the purchasable packs. (I don't post the code here because I don't know if I'm allowed since the ANE is licensed.)
My app works that way:
First screen : Logo with a link to the website and a "Enter" button.
When clicked, the user arrive on a screen with a few buttons (one for each pack/country).
If the user click on a pack he owns, he is send to the chosen country's map.
If he doesn't own it, he is asked if he'd like to buy it and send to buy it.
Problems: (warning: some of those are worthy of noob of the month status, but I'm here to learn right?)
The code adapted from the Milkman's example is in an outside .as file used as DocumentClass.How do I link my screen 2 buttons with the functions from the .as file?
I tried this, but it doesn't work:
franceBtn.addEventListener(MouseEvent.CLICK, checkAndPurchase);
function checkAndPurchase (e:MouseEvent):void{
purchasePack1();
//function from the example, it checks if the pack is owned
// and send the user to the store if not
};
EDIT 1: It is probably really easy to do, but I'm just not experienced enough to understand what I need to do I guess.
I have a series of buttons in my app (say "franceBtn", "usaBtn" and "ukBtn"). Those buttons, when clicked, need to check if the pack ("francePack", "usaPack" and "ukPack") is owned by the user and if it is not, start the in-app purchase. I have tried to add an EventListener to the buttons, but nothing happens. Not on screen, not in the log.
2.Let's say the problem 1 is fixed. My app is meant to be used offline (except for buying additional packs). The way I understood what I read is that the "inventory" of in-app purchased packs is obtained via Google Play, which means (if I'm not mistaken) that the user needs to be online. Is there a way to create a file of some kind inside the device that stores this "inventory" so it can be accessed offline?
EDIT 2: I want the user to be able to use the app from everywhere, without the need to be online (except for purchasing packs obviously). But I guess that the app checks with Google Play in order to know which pack is already owned. So I'm looking for a way to store the "inventory" of owned packs directly inside the device/app (so it can be accessed offline and updated everytime internet starts.
I hope it is more clear, and thank you for pointing out it was not.
I've read the doc quite a few times, and I'm really stuck, so please, I'd really appreciate any help. ;)
Thanks in advance,
Jeryl
EDIT 3: Here is the portion of my code relating to IAB (made by following this tutorial :here but I didn't really understand it. I'm willing to learn but this is an intermediate level tuto, and I've found nothing on Internet that explains what to do for real beginners. If you have links I couldn't find, I'm all hears :D )
import com.milkmangames.nativeextensions.android.*;
import com.milkmangames.nativeextensions.android.events.*;
import flash.events.MouseEvent;
if (AndroidIAB.isSupported()) {
AndroidIAB.create();
}
// listeners for billing service startup
AndroidIAB.androidIAB.addEventListener(AndroidBillingEvent.SERVICE_READY, onReady);
AndroidIAB.androidIAB.addEventListener(AndroidBillingEvent.SERVICE_NOT_SUPPORTED, onUnsupported);
// start the service
AndroidIAB.androidIAB.startBillingService("my_key");
function onReady(e: AndroidBillingEvent): void {
trace("service now ready- you can now make purchases.");
}
function onUnsupported(e: AndroidBillingEvent): void {
trace("sorry, in app billing won't work on this phone!");
}
// listen for inventory events
AndroidIAB.androidIAB.addEventListener(AndroidBillingEvent.INVENTORY_LOADED, onInventoryLoaded);
AndroidIAB.androidIAB.addEventListener(AndroidBillingErrorEvent.LOAD_INVENTORY_FAILED, onInventoryFailed);
function onInventoryLoaded(e: AndroidBillingEvent): void {
for each(var purchase: AndroidPurchase in e.purchases) {
trace("You own the item:" + purchase.itemId);
}
}
function onInventoryFailed(e: AndroidBillingErrorEvent): void {
trace("Something went wrong loading inventory: " + e.text);
}
// load the player's current inventory
AndroidIAB.androidIAB.loadPlayerInventory();
// listen for purchase events
AndroidIAB.androidIAB.addEventListener(AndroidBillingEvent.PURCHASE_SUCCEEDED, onPurchaseSuccess);
AndroidIAB.androidIAB.addEventListener(AndroidBillingErrorEvent.PURCHASE_FAILED, onPurchaseFailed);
function onPurchaseSuccess(e: AndroidBillingEvent): void {
var purchase: AndroidPurchase = e.purchases[0];
trace("you purchased the item " + purchase.itemId);
AndroidIAB.androidIAB.loadPlayerInventory();
}
function onPurchaseFailed(e: AndroidBillingErrorEvent): void {
trace("Something went wrong with the purchase of " + e.itemId + ": " + e.text);
}
franceBtn.addEventListener(MouseEvent.CLICK, onPackOneButtonClicked);
function onPackOneButtonClicked(e: MouseEvent) {
if (purchase.itemId == "packone") {
franceMap.visible = true;
} else {
AndroidIAB.androidIAB.purchaseItem("packone");
}
}
Thanks for your patience! Jeryl
Before proceeding, I am assuming that you have properly set up the products in IAP section of Google play.
Now for your first question, I am not sure about the problem as clicking on a button and something to be done on that event should have worked out of the box. Your code should be something along the lines:
( Assuming you have two packs and their itemIds are com.yourcomapny.packOne and com.yourcompany.packTwo)
franceBtn.addEventListener( MouseEvent.CLICK, onPackOneButtonClicked );
function onPackOneButtonClicked( event:MouseEvent )
{
if( !isPackOnePurchased() )
{
purchasePackOne();
}
}
// Similarly for pack two
This is pretty much the same code , you are trying to write. Perhaps we can help you more with your problem, if you can post some portion of the code which is not working.
For your second part, if you want to store the "inventory" information offline, you may proceed in the following way:
1) Lets say you create an empty file.
2) Lets say if a person buys com.yourcompany.packTwo and you received purchase Successful event, you just add com.yourcompany.packTwo to the file and thus marking it as purchased.
3) Whenever you call isPackOnePurchased or isPackTwoPurchased, it checks whether corresponding itemId is present in the file and decide whether this package needs to be bought or it is already bought.
This will get you started. Another thing for enhanced user experience and security is that whenever user clicks on a button to buy the pack ( and he/she is connected to the internet ), always check whether that pack is in the inventory or not and show the feedback according to that. Always sync your local state with inventory, if there is any inconsistency. The inconsistency may arise if user deletes their application data and then tries to open the pack. This check will ensure that your application is synced with server state.
If you want next level of security you can either encrypt the information( item Ids in this case ) and store it a secure database.
Encryption can be done using numerous encryption methods. One such method is Rijndael encryption. You can use this tool this online tool for generating encrypted strings for your itemIds. This will give you a feel of what I am trying to say.
For how to store information in local database in an AIR based applications, see this link from Adobe

Android - Windows Live API, User has to sign in every time?

I am trying to submit a status from my application to Window's live, the user starts the app, gets asked to give my app permissions to do this, and once granted I have a live session object and I can update their status. This works perfectly.
However, if the user closes the application and then opens it again, they are again asked to approve my app for this action. Every time.
Now the live documentation says you can obtain a refresh token (which I do) to prevent this, problem is the access token and the refresh token are all baked in the LiveConnectSession, so when my application is closed this object is destroyed and the user is asked to give the app permissions again.
So what I'd like to know is if anyone knows a way of recreating that object when the application starts (if I stored the token and refresh token) or a way of saving the object onDestroy()..
Iterable<String> scopes = Arrays.asList("wl.signin", "wl.share", "wl.offline_access" );
this.auth.login(this, scopes, this);
public void onAuthComplete(LiveStatus status, LiveConnectSession session, Object userState) {
if(status == LiveStatus.CONNECTED) {
Log.d("", "Signed in.");
client = new LiveConnectClient(session);
stuck with the same issue using Windows Phone..
I have tried serializing the session, which does not work because the session class has no default constructor.
EDIT:
after two full days searching for the mistake I was making, I finally found out what I was doing wrong: I have to use the wl.offline_access scope to make this work!
Now everything is fun again. Can't believe that this was the problem. Tested & working. Nice!
As I can see, you are using the offline scope, so that's not the problem for you.
But I have found out more:
there are two ways to connect to Live (in C#, I don't know how the methods are called in Java):
use LiveConnectClient.LoginAsync (which comes with GUI)
use LiveConnectClient.InitializeAsync (which is UI less and connects in background)
So if your application is already connected, use the second one to gain access to a new session object.
AFAIK, this object is valid for one year, after that, the user has to sign in again. But don't quote me on that.
Please let me know if this works for you.

Categories

Resources