For some odd reasons, I am unable to get the developerPayload. I'm using the Dungeons Example. I have seen this work before, I think the payload string should appear in the Recent Activity. As far as I know, it should work if I'm using an actual product ID (like, potion_001). The whole purchasing works very well, but alas, the developerPayload is not there. I have barely made an edit with the Dungeons sample apart from renaming the package name. I did try to edit the intent actions, though:
public static final String ACTION_CONFIRM_NOTIFICATION =
"com.blah.something.dungeons.en.CONFIRM_NOTIFICATION";
public static final String ACTION_GET_PURCHASE_INFORMATION =
"com.blah.something.dungeons.en.GET_PURCHASE_INFORMATION";
public static final String ACTION_RESTORE_TRANSACTIONS =
"com.blah.something.dungeons.en.RESTORE_TRANSACTIONS";
It still didn't work. I have been re-reading the in-app billing docs, but I'm not sure if I'm missing something here. Is there something that I may have missed, or misconfigured in the android market options and/or the dungeons sample?
You are not receiving the developerPayload in DEBUG MODE. You need to sign your application to RELEASE MODE to receive developerPayload.
It works now. For some odd reasons, the developerPayload just came back. There was also someone in the net who had the same problems as I am, and it also happened just last weekend (http://www.google.com/support/forum/p/androidmarket/thread?tid=197b77d86cbb09ff&hl=ja). It's in japanese, though, but basically he also had problems with developerPayload being null, and then it also came back again a few days later. I also live in japan, so I guess this might have happened only in our area. I guess it really was true, that transferring payload is quite a heavy workload for google.
Related
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.
Our beta app uses android.test.purchased so customers can test for free. But recently something broke with consuming these test products. The purchase process still works fine but when we try to consume:
int response = ms.consumePurchase(3, mContext.getPackageName(), token);
This now always returns RESULT_DEVELOPER_ERROR == 5. The data passed appears valid, token is inapp:com.lootworks.swords:android.test.purchased which I think is correct for the static test products.
Simultaneously all our earlier app versions also stopped working and we did not change our code, so it sure seems like something changed with IAB itself.
I also tested purchase/consume of the real (for $) products and it succeeds with the same code. So the consume problem seems to affect only the static response test item.
With Sean's help and some additional testing this appears to be a google play IAB regression. Have opened a bug https://code.google.com/p/android/issues/detail?id=53077
My team and I are experiencing this same issue. Nothing has changed with the app consume code, so it is very strange. The app is not release-ready yet, so we have plenty else to work on, but this throws a monkey wrench into testing for sure.
This may not be an option for you, but you could change the namespace, delete the app entry in the dev console and go through the process of making a new one, and splitting the key up again, etc.
I only suggest this because this problem does not seem to be happening for all apps. Anyway, if the consume in our app does not start magically working again soon, this is what we will try.
First thanks to Google for the new IAB it is much easier to use and it has a more complete feature set.
However i think i hit a "small" issue when testing it with the static responses from Google Play.
Following the guideline and making use of the helper classes in the example implementation it seems that you never get the result back on your activity onActivityResult if you start a purchase with one of the test products.
So after a bit of digging it seems that, at least for those products, it still starts the previous implementation IN_APP_NOTIFY broadcast. Has any of you stumble on this issue?
Thanks in advance
EDIT:
got this line in logcat:
D/DfeApi(1367): [1] DfeRequest.deliverResponse: Not delivering second response for request=[[ ] https://android.clients.google.com/fdfe/details?doc=inapp:com.mobizy:android.test.purchased NORMAL 103]
EDIT:
ok so it was a blunder. what happened is that there was a codepath that ignored the onActivityResult. So it's fixed and it's working ... Thanks for the replies people.
Hm, that is not my experience. The 'purchased' product seems to work just fine: displays FAKE card and I can buy 'gas' for the sample app. But they don't mention it in the documentation though, so the static responses are probably not really supported.
Is it possible you didn't clean up your AndroidManifest.xml? The 2.0 implementation had you register receivers for the various IAB messages.
When I upgraded to 3.0 I had to remove those receivers as its all handled by the IabHelper.
I'm trying to create a SyncAdapter for my Android app to show YouTube videos from one specific channel. The videos are public domain so I don't want the user to login, create an account, authenticate themselves, upload data, or use the contacts database. I simply want the SyncAdapter to periodically update my app's database with the newest video metadata from that channel. I already built a ContentProvider to access my database. I do like the fact that the SyncProvider will handle the ability to turn off syncing, scheduling, and retry backoff mechanisms for updating.
I asked earlier if a SyncAdapter was a good choice for my use case, and I was told it was. I watched the Google I/O video, read the docs, read blogs... (see list below). I've been unable to get anything to work. The best I've gotten was to have the SyncAdapter account show up in the global "Accounts & sync settings" but be non-functional. Even if this worked, it would be less than ideal because I prefer the user to not see the account except from inside my app. This would be acceptable if there was no other option, so long as they don't need to access it to set it up as everything would default to automatic once a day syncing.
I even tried to use the SampleSyncAdapter as-is and put breakpoints in the Authentication code sections. Not a single breakpoint is hit so I can't see what triggers the calls or what data is contained. I would have thought I'd at least get that much.
I'm starting to think using a SyncAdapter is a bad idea despite the recommendation. I've yet to find an example that is close to what I want, let alone a tutorial or complete, organized and clear docs. This seems like it should be a common task many apps would want to do.
Please add to this post any good documentation on this use case. I can find none.
Without this, I think it's fair to recommend to everyone to not use SyncAdapters for this use case. I'm not speaking for other use cases here so don't jump on with how it worked for your use case if it's not like mine.
It would also be helpful to know what version of the API level is considered ready for primetime. There's a number of issues posted regarding version numbers. I'm trying to stay as low as possible to get the most users. My current API target is 7.
Here's list of links I've tried to no avail, others may find these more helpful:
http://developer.android.com/resources/samples/SampleSyncAdapter/index.html
http://www.google.com/events/io/2010/sessions/developing-RESTful-android-apps.html
http://naked-code.blogspot.com/2011/05/revenge-of-syncadapter-synchronizing.html
http://www.c99.org/2010/01/23/writing-an-android-sync-provider-part-1/
http://www.c99.org/2010/01/23/writing-an-android-sync-provider-part-2/
http://www.finalconcept.com.au/article/view/android-account-manager-step-by-step
http://www.finalconcept.com.au/article/view/android-account-manager-step-by-step-1
http://www.finalconcept.com.au/article/view/android-account-manager-step-by-step-2
Android SyncAdapter without Authentication vs. Android Service
Why does ContentResolver.requestSync not trigger a sync?
In short the answer is: ContentProvider, AccountManager and SyncAdapter go together. You must have these three pieces, even if they are "dumb".
As stated above, "ContentProvider, AccountManager and SyncAdapter go together".
For your application you can call the following activity the first time your app is loaded to authenticate and start synching automatically:
public class LoginActivity extends AccountAuthenticatorActivity {
private final static String DUMMY_ACCOUNT_NAME = "some_name";
private final static String DUMMY_ACCOUNT_PASS = "some_pass";
private final static String AUTHORITY = "com.android.contacts"; // for example
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Account account = new Account(DUMMY_ACCOUNT_NAME, Constants.ACCOUNT_TYPE);
AccountManager am = AccountManager.get(this);
if (am.addAccountExplicitly(account, DUMMY_ACCOUNT_PASS, null)) {
Bundle result = new Bundle();
result.putString(AccountManager.KEY_ACCOUNT_NAME, account.name);
result.putString(AccountManager.KEY_ACCOUNT_TYPE, account.type);
setAccountAuthenticatorResult(result);
ContentResolver.setSyncAutomatically(account, AUTHORITY, true);
}
finish();
}
}
This works in Android API 5+.
I've been playing around the the Dungeons app and also my own billing code and pretty much have everything working except for one strangeness.
It seems that no matter what I do I can't get the DEVELOPER_PAYLOAD to show up in the JSON signed response. If I'm reading thing right, the docs seem to say that I should see the developer_payload in the JSON market response. The Dungeons app seems to think it should see the developer_payload in the json too.
I haven't gotten it to work in my code and it doesn't seem to work in the Dungeons example either on my phone.
Here are some snippets of my code:
Bundle request = makeRequestBundle("REQUEST_PURCHASE");
request.putString(C.DEVELOPER_PAYLOAD, "testing 123");
C.DEVELOPER_PAYLOAD is:
public static final String DEVELOPER_PAYLOAD = "DEVELOPER_PAYLOAD";
And here's what I'm seeing in the purchase state changed responses
05-14 20:13:08.360: INFO/BillingService(715): purchaseStateChanged got
signedData:
{"nonce":9005407554096378381,"orders":[{"notificationId":"android.test.purchased","orderId":"transactionId.android.test.purchased","packageName":"com.mypackage","productId":"android.test.purchased","purchaseTime":1305429187752,"purchaseState":0}]}
Thanks in advance!
EDIT: I finally figured this out. Turns out that the developer_payload doesn't come through if you're using any of the test android item ids. You have to be using real in app purchase items.
I finally figured this out. Turns out that the developer_payload doesn't come through if you're using any of the test android item ids. You have to be using real in app purchase items.