I'm having trouble figuring out how the in-app billing process is supposed to work for broadcast events when the application isn't running. I have a managed product setup and as far as I can see, is working well. With a test account I'm able to purchase my published component and my test application handles it, retaining its state. I then cancel this order via my merchant account and the application again receives the event and removes the item.
The problem occurs when instead of cancelling the order while the application is active. I exit out of it (not with home, with multiple back buttons). If I cancel the item now, my 'device' gets a notification 'purchase failed', but when I start my application nothing seems to happen and thus the state of the item is still purchased.
I'm not sure if billing service is still running or not. Given the documentation says my application must send back a CONFIRM_NOTIFICATIONS or it keeps sending it I can only assume it is. However why is it unable to interact with my database and remove the item like it does correctly if the application is active?
I hope tihs is clear, and I apologize if it has been discussed before, I couldn't find anything in my searches.
Apologies for answering my own question but hopefully my findings will help others that were confused as I was.
My issue was thinking that the Dungeons.java class provided in the example had all the code needed for modification. The example design has its database implementation nested in the observer class that is active while the user is interacting with the store. The issue it created for me outlined in my question, what happens if a transaction is cancelled after the fact when this observer isn't registered or the application isn't running.
From trial and error my solution was to take the database interaction out of the observer and place it in
private void purchaseStateChanged(int startId, String signedData, String signature) {
of the BillingService class.
Placed in here, when my broadcast receiver fires, I act on a cancellation and update my database accordingly regardless of whether my application is started much less my observer registered.
Related
I have a system where one user can be logged into multiple devices. The use case is as follows:
Suppose the user A subscribes to a weather topic from device A. This user will now get regular push messages from this topic.
Now assume that the same user is logged in to a device B. This device also needs to get subscribed to the weather topic as there is no gurantee that the user will just use device A.
Same use case can be applied in reverse case of unsubscription as well as more than two devices.
What is the best possible way to solve such a problem.
The current approaches which i have thought of are:
1) Make a node under each user id inside firebase db called subscriptions. This node will have subscribed data in the form of
Topidname :boolean issubscribed
This approach has a listener attached to this location in a background service. Each device with the same user id will always listen to the same location thus solving the issue in most cases. It can't gurantee integrity due to the normal service lifecycle reasons.
A service is used because if the listener is kept only for the lifetime of the app, if the user unsubscribes from a topic on one device and the second device app is closed, the second app will keep receiving notifications as it's registration token is still related to that topic and will only unsubscribe on app restart.
Here the service has been made START_STICKY, has a listener inside onCreate and has a backup alarm set to restart the service in onDestroy method. Thus the only case where this won't work is an app force stop or the listener being in a backoff mode due to long non connectivity.
When the app launches it also syncs once with the location and subs the left out topics. Service will stop on signout and unsub from all the previous user's topics. I have kept a keepSynced on the location to ensure it stays in sync
Potential issues are -> service killed by force stop. May cause some ram usage. Sync might not be instantaneous depending on how long the connectivity was lost and how long it takes firebase to resync with the db. Resync and sub unsub all topics in each service restart.
2) This is a relatively more complicated approach:
Save the firebase token from the instance id service for each user in the app server.
On each signout, instead of calling delete iid, keep the same token but overwrite the user attached with the new logged in uid.
On each subscription, do a bulk subscribe to the topic using the Instance Id server api using all the registration tokens for one user.
Each time a user signs out call unsubscribe on all the topics one by one using the instance id api for that device's particular token. Same process for token refresh.
Do to same on unsubscription of each topic.
This case will need one synchronous call for all the topics subscriptions and unsubscriptions. It will also require the token to be constantly updated in the app server.
Please suggest any other better scenario to solve this issue.
If my scenarios have any flaws or needs modifications, please do suggest. I'm stuck and can't think of anything else at the moment.
I'm assuming that you're keeping track of each of the tokens for a user's devices. So the code on your server should be able to know, for a given user, how to send a message to all of their devices, regardless of subscriptions.
Try thinking of user topic subscriptions in the same way that you think of the data broadcasted within those topic. When topic subscriptions change for a user, that event could be broadcast to all of their devices with FCM, telling your app to read the subscriptions from your database and set subscriptions again as necessary. Your app will only wake a receive a notice to change subscriptions when the user requests it.
Then, when it comes time to publish a message to the topic, you can be sure that all the devices that checked in like this will receive the message to the topic.
To boil it down:
1. When a user's subscriptions change in your app, notify the server of that change.
2. In your server, update the user's subscriptions to your database.
3. Then, send an FCM data message to all of the user's devices to reload subscriptions.
4. When that message is received in your app, read the subscription updates out of your database and update the FCM subscriptions accordingly. Your app will have to arrange to stay alive for as long as it takes to do this.
in my app I am using push notifications to notify the user about something.Based on different app state I have to assign different activities to click event of notification. If the user press home button and app is in background i have to handle that scenario as well. But here the issue come when user clear the app instance from memory. If user do that I have to consider it as app closed. But i dont know how to get that app instance clear event. Please help me.
The task you are willing to solve is equivalent to protection against the task manager. I am not sure that your app knows better than the user whether or not to show the ads. Please do not create malware.
Try the UncaughtExceptionHandler stuff like setUncaughtExceptionHandler(). I am not sure it will be necessarily called, and it may depend on the Android version, but it is something to start with.
Another possibility is to use one or more remote service(s). The processes will not die all at once, there's a good chance that one process may notice the death of another process. There should be some kind of wait-for-process-to-complete at least on the JNI level.
One more possibility is to use two applications, one monitoring the other...
After you solve this problem, please post your own answer telling the world what you did.
I have a very common problem but wasn't able to find a proper solution/pattern to solve it. My application has two kinds of data that need to be automatically updated:
general data
user-related data
If the user is not logged in, only general data are downloaded and displayed, if the user is logged in, his/her data are handled too.
I need to periodically download these data from a Web service, starting from the boot of the device (after the action android.intent.action.BOOT_COMPLETED is triggered).
Since my app can be moved to the SD, I will also need to register for the android.intent.action.EXTERNAL_APPLICATIONS_AVAILABLE action.
Issue 1: starting from API level 11 (Honeycomb) all actions aren't sent to applications in a stopped state. I haven't quite understood this, does this mean that my app can't listen for actions if it has just been installed and never opened (so only once if we count updates out)? Or does this mean that, after every system reboot, the action will be triggered only when the application starts?
Issue 2: if the application has been moved to SD, SyncAdapters won't be able to be run, so I have to rely on the general BroadcastReceiver-Service-Alarm-PendingIntent strategy. But how can I understand if the SyncAdapter won't be started by the system? (I already handle Accounts by the AccountManager)
Do you know of any library that takes care of all of this? It seems quite strange, isn't this a common issue?
Re: issue 1, as far as I can tell, an app is not "alive" until the user explicitly runs it for the first time. It will then still be "alive" until the end of the days, unless the user explicitly stops it using the Force stop button in Android's Applications management settings. He will then have to re-run manually the app for it to be able to receive broadcasts and stuff.
Ahh the in-app billing problems never end! ^.^ I have everything working properly to show the transaction page for the in-app purchase. If I complete the purchase it returns me to my application and after about 10 seconds it verifies the purchase and I receive the item.
On the other hand, if I press the back button after returning to the application and switch to another activity it never processes the transaction. Even if I return to the in-app billing activity I never receive my purchased item, like the purchase has been completely forgotten about if you call finish().
What can I do so that it either completes the transaction and gives the item when I return to the in-app billing activity or processes the transaction and gives the purchased item anywhere that I am at within my application?
Receiving the notification is handled by a broadcast receiver which is independent from your activities. How you handle the notification is up to you. In the default implementation you have a PurchaseObserver interface implemented by an Activity. You can have multiple activities implement it and register to be called accordingly. Or, you can have related code in a base activity, so that all your activities are PurchaseObserver's (might not be practical if you have a lot of activities).
The official documentation says that "Your application must have a local Service to facilitate messaging between your application and Android Market."
My question is, is this is really necessary? And if yes, why?
Wouldn't it be possible to simply bind to the MarketBillingService from an Activity's onCreate method without having to creating a local service first?
Having to create a local service that forward the requests to the remote MarketBillingService just seems a bit over-complicated.
I agree that the In-App Billing example application has a number of layers to it that seem unnecessary, but the idea of using a Service to interact with Market is a good one. This is because the process is very asynchronous (and can take a good amount of time) and some events are generated outside the workflow of a user purchase.
While the user will be interacting with some Market UI while deciding whether to purchase the "item", after this process is over there is a long back-and-forth between your app and the market app to authorize and finalize the transaction, many steps delayed while Market communicates with its servers. You don't want to hold the user up and force them to wait on that Activity simply so you can complete the purchase. You want that to be in a Service so the user can move around in the app, or leave it completely for awhile, and still be able to finalize the purchase and download the appropriate purchased content without fear of your process being removed.
Also, there are many events that may come into your application if purchases are canceled or otherwise rejected that can happen LONG after the initial purchase back-and-forth, and the user may be doing something completely different or not have their phone awake at all at that time. You want to be able to handle these events without having to pop up an Activity.
Bottom line, it's a long-running background process...which is what Services were designed for.
HTH