I'm using the Play Billing Library in order to trigger and manage purchases which in turn unlocked extra functionality within an app. This part is working.
However, what is the best way to 'restore' purchases. Say for example someone who has bought the app buys a new phone. Logs in to the Play Store, downloads my app and then finds that the payment screen to 'upgrade' is being displayed. iOS has a specific method for this but I'm not aware of one for Android.
My thoughts are to query the Play Store and confirm whether the account has previously SUCCESSFULLY purchased the item, if so then I will call the local upgrade function within the app.
It appears there are two similar methods. But which one should I used in this scenario? Where a user has either wiped their phone or bought a new one?
queryPurchases()? Or queryPurchaseHistoryAsync()?
You should use queryPurchases. That gives you all the current active (non-consumed, non-cancelled, non-expired) purchases for each SKU.
queryPurchaseHistoryAsync won't do what you need because it will only give you a list of the most recent purchases for each SKU. They may have expired, been cancelled or been consumed, and there's no way to tell. Therefore this response can't be used to tell what purchases to apply in your app.
So far as I can see, the only valid use for queryPurchaseHistoryAsync is to provide a user with a list of their purchase history. It's a bit of an oddball.
Note also: queryPurchases is synchronous so in most cases it needs to be run in some kind of background worker thread. I run mine in an AsyncTask.
Per documentation queryPurchases uses the Play Store app cache to get the results while queryPurchaseHistoryAsyncactually checks the Purchase AP for the most recent purchases. So, in your case you should check the Asyncmethod.
queryPurchases
Get purchases details for all the items bought within your app. This method uses a cache of Google Play Store app without initiating a network request.
queryPurchaseHistoryAsync
Returns the most recent purchase made by the user for each SKU, even if that purchase is expired, canceled, or consumed.
Also, make sure to check the documentation. It recommends to Cache purchase details on your servers.
https://developer.android.com/google/play/developer-api.html#practices
I know it's a bit late, but I just discovered this myself. Sharing my answer for others to benefit.
So I learned that queryPurchases() is cached locally on your device, but is updated when you call queryPurchaseHistoryAsync()
I discovered from this Stackoverflow answer here
So my solution, is when wanting to restore a purchase on a new device, or a fresh install of my app. Call queryPurchaseHistoryAsync() Then in the callback onPurchaseHistoryResponse() call queryPurchases() and look within the List<Purchase> from the PurchasesResult for the purchase status of any of the user's past purchases.
If there's an expected purchase your app can grant the entitlements of their past purchase.
The documentation has been updated for the latest versions of BillingClient. queryPurchases() is deprecated. Also note that queryPurchases() only ever returned purchases made by the current device, so that method will not inform your scenario of a new wiped phone. To get accurate information use the async calls.
queryPurchasesAsync() will return all active subscription and unconsumed one-time Purchase objects for the sku type provided. It gets the purchases from the local Play Services cache, so there are no guarantees the cache will contain purchases from another device in your "new phone" scenario, and no guarantees the cache will yet be current in your "wiped phone" scenario.
queryPurchaseHistoryAsync() will make a network request and return the most recent PurchaseHistory object for each sku matching the provided sku type, even if cancelled or consumed.
Also, to perform the upgrade call launchBillingFlow() with the appropriate BillingFlowParams and BillingFlowParams.SubscriptionUpdateParams for the sku you now know to be purchased.
Related
I am using in-app billing from this link: https://github.com/anjlab/android-inapp-billing-v3
it allows me to purchase the item one time only. so I googled how to be able to purchase it more than one time all results lead that I need to consume the old purchase. I cannot find how and were to call the consuming function
here is the consuming function:
billingProcess.consumePurchase(n_Selected)
I tried to call it in the onCreate method: it did not do anything
I tried to call it in onProductPurchased method: it did not do anything
You should consider Google Play's official Billing Library. Add
com.android.billingclient:billing:2.0
to your build.gradle.
https://github.com/googlesamples/android-play-billing/tree/master/TrivialDrive_v2
is Google's best practice.
You should always call queryPurchases and call consumeAsyc for outstanding purchases in the callback. Also, call consumeAsyc in onPurchasesUpdate method, which is triggered after a successful purchase.
I'm in the middle of developing an Android app using Firebase, and have Phone Number Authentication enabled as a method of user sign-in. This all works fine.
Inside my app, I have an Account Details page that allows the user to edit their information and update their record in the FirebaseDatabase (in a separate node that I have created and called users). I'm able to update this table with no problems, but I need to update the table that Firebase keeps when users register, so that phone numbers don't get out of sync.
In theory, it should be really easy to do. I've done some reading up and seen that a method exists in the FirebaseUser class called updatePhoneNumber(PhoneAuthCredential). The only problem is that I have no idea how the PhoneAuthCredential class works and, after a couple of hours of Googling, haven't been able to find a single example, or many other forms of support for the method.
An example for the FirebaseUser.updateEmail(String) method can be seen here, so I'd guess that it can't be all that different, and should work fine if I can get the PhoneAuthCredential object set up correctly.
Update:
I tried to create an instance using new PhoneAuthCredential(...), but the suggested parameters aren't much help...
Android Studio displays the constructor as public PhoneAuthCredential(String s, String s1, boolean b, String s2, boolean b2, String s3), so I am very much none-the-wiser.
If I can figure out how to use this constructor, I might well be off the ground, hopefully.
If anyone can advise on how to use PhoneAuthCredential, or how the FirebaseUser.updatePhoneNumber() method should be implemented, that would be a huge help!
Thanks in advance,
Mark
Phone auth is quite complicated, so I'd recommend reading this guide. This section is especially relevant to your case. Basically, you'll have to go through the entire phone auth flow again to get a credential and set the user's new phone number.
If you're thinking of the phone number as a part of the user's profile, that's incorrect as you can see from the profile request. The phone number is considered to be a sort of user identifier, like the email which also requires a credential if the user's sign-in action is 5 mins old. Hope this helps!
I'm using Android Studio to create an app that utilizes google maps api. I am having trouble validating if the user input is an actual location.
i.e if the user enters "fdfdfaef", program crashes.
i have the following code to store the user "location" input:
address = geocoder.getFromLocationName(location, 1)
Any help on how to check if the input is valid or not or at least to prevent a crash. Thanks and appreciate it.
Since you haven't posted any code, I will go out on a limb and suggest that you might be doing this on your main UI thread.
From the doc,
The query will block and returned values will be obtained by means of
a network lookup. The results are a best guess and are not guaranteed
to be meaningful or correct. It may be useful to call this method from
a thread separate from your primary UI thread.
Try doing a async task that requests information using the Geocoding API. On getting a result, update the UI. Offloading to an AsyncTask will prevent the crash, at the very least.
Does that help you?
I am creating an app that checks for user locations every half an hour and updates the location of the user in the local database and then runs CRUD queries based on the user's location even when the app is not running. How do i do it ?
I have referred to this http://techtej.blogspot.com.es/2011/03/android-thread-constructspart-4.html article and i am still confused about which is the correct approach for my result ?
There are 4 options according to the article for what i intend to achieve according to me
1) Service : But since i feel it would be a long operation with the local database, i feel i should ignore this one.
2) IntentService : This cannot perform multiple tasks, so i feel this one also should be avoided for me as i have to get the location of the user and scan the database , update the database (3 tasks)
3)Thread : I am not sure how to call this when the app is not open
4) AsyncTask : I am not sure how to call this when the app is not open.
Basically i looking for something like a CRON JOB that runs on a local database while working on the location data.
It would be great if you could link me up to some tutorials and answer with a simple example to make me understand the difference of all 4 methods.
// editted on 16 March :
I have read something about a JobScheduler which is introduced in the API 21, but not sure if it also supports till Gingerbread and is it the right approach for my question
Thanx
When recording the users position use a service with a notification. Just for the sake of creating a morally responsible app that informs the user the app is tracking them. The service by definition runs in the background.
A fused location provider with setinterval(long) 30 minutes gets the interval. Set fastestInterval() to a minute to receive GPS data when other apps are using the GPS.
Have you considered using a SyncAdapter. Its best to schedule jobs at fixed interval and also optimized for battery usage. Also, once started, it can run independently of the app. As per your requirements, I believe this is best suited for your need. You can read about this here. This also removes the corner case of starting the service (generally used) when your device is restarted. Your app will still continue running the scheduled job even if the device gets restarted.
In the SyncAdapter you have to use a ContentProvider so wrap your DB inside a ContentProvider. Also, preferably use a CursorLoader to run longrunning tasks on DB. You should read about CursorLoader. This is a great way to access your resources. Also, you can define an Observer Design Pattern which Observes for changes in a DB and will perform a task when changes are made in DB. This can also be used inside your application itself and also inside SyncAdapter. Cursor Loader is best preferred for background work on DB. You can perform all CRUD Operations using a CursorLoader and ContentProvider.
This cannot perform multiple tasks
Yes, it can. It has only one thread, and so it can only do one simultaneous task.
i have to get the location of the user and scan the database , update the database (3 tasks)
I have no idea why you think that is three tasks. You cannot do them simultaneously.
Your bigger problem with IntentService is that getting location data is asynchronous, and IntentService is not well-suited for calling APIs that themselves are asynchronous.
But since i feel it would be a long operation with the local database, i feel i should ignore this one.
The point behind any service is for "a long operation".
Basically i looking for something like a CRON JOB that runs on a local database while working on the location data
Use AlarmManager to trigger a WakefulBroadcastReceiver, which then triggers a Service. The Service, in onStartCommand(), forks a background thread to (asynchronously) retrieve the location and update the database. The Service can then call completeWakefulIntent() on WakefulBroadcastReceiver, plus stopSelf() with the startId received in onStartCommand() for this work, plus allow the thread to terminate. If no other commands were received in the interim, the service will shut down.
I think you are looking for something similar to WakefulIntentService. This handles all your cases completely.
You can do your location and db related work inside doWakefulWork() of said implementation.
I've done what you are looking for, both with GPS and non-GPS.
The project I took as staring point for the non-GPS solution already does all you need, and is battery-friendly (credits should go to Kenton Price):
https://code.google.com/p/little-fluffy-location-library/
Take a look at it, it works like a charm. Just run it in any device. If you need any help customizing just let me know.
Just edit the "onReceive" method in the "TestBroadcastReceiver" to update your DB.
If you need the GPS solution let me know too, but I dropped it for being a battery killer!
Hope it helps.
1. I think for this requirement, Thread and inside it AsyncTask -- this structure will be useful.
In link provided by you, it is mentioned very nicely here
2. For location related blog, you can check useful materials here :
(1) Difference between Google Map Distance and Directions API
(2) Check this answer also
Hope this will help you
I am currently looking at a system that implements the PayPal api. As a part of this I need to get the feeAmt() which is the fee that is paid to paypal for processing the payment.
From the documentation that I have looked at it appears that I have to implement the getExpressCheckoutDetailsReq() method in order to get the information that I want however no matter what I have tried I am struggling to do this. I should also let you know that I am currently developing my application using Java so using this is going to be best.
If any more explanation is needed please don't hesitate to ask and I will do my best to amend the post :)
GetExpressCheckoutDetails does not include the fee because at that point no payment has been made yet. That's the 2nd of 3 calls for Express Checkout, and until the final call is made there is no fee.
The fee amount would actually come in that final call's response: DoExpressCheckoutPayment. It will come in the PAYMENTINFO_n_FEEAMT parameter, where n is the number of the payment (0,1,2,etc.) Most likely it'll be 0 unless you're working with parallel payments.
Alternatively, you can use Instant Payment Notification (IPN) to get details about transactions, including the fee, in real-time when transactions are completed on your PayPal account.
Yet another option would be to use the GetTransactionDetails API to pull data for an individual transaction which would include the fee in a FEEAMT parameter. Maybe that's the one you were initially thinking of..??