android In app billing strange execution - android

I am working on in app billing of android..i follow tutorial of android and currently i am testing for test app.(android.test.purchased)
I create app on google console
I sign apk and upload it to google console than i copy public key and paste it into my code and sign apk again and install it on phone than i tried to buy test purchased id It display me purchased successful but in my Log value i display the purchaseddata and datasignature and i got datasignature NULL (empty)
The fun part is in handleActivityResult method there is one if condition which checks weather datasignature or purchaseddata is Null or not and in my code it does not execute if skips it ? how it is possible?
Here i pur log but in my logcat i cannot see "In BUG Null value"
if (purchaseData == null || dataSignature == null) {
logError("BUG: either purchaseData or dataSignature is null.");
Log.e("Inapp", "In BUG Null value");
logDebug("Extras: " + data.getExtras().toString());
result = new IabResult(IABHELPER_UNKNOWN_ERROR, "IAB returned null purchaseData or dataSignature");
if (mPurchaseListener != null) mPurchaseListener.onIabPurchaseFinished(result, null);
return true;
}

I had this problem myself. After a while I found what I did wrong. I was calling the wrong method on the IABHelper.
If you call mHelper.launchPurchaseFlow(...) with an SKU that is registered as a subscription on Google Developer Console it will result in the error: IAB returned null purchaseData or dataSignature (response -1008:Unknown error).
If you have a SKU that is registered as an subscription you have to use the method: mHelper.launchSubscriptionPurchaseFlow(...) instead.
Hope this helps.

Related

FireStore Database set never calls OnSuccessListener or OnFailureListener

The Firestore database set() does not call OnSuccessListener or OnFailureListener and don't writes the data to the database online!
As you see in the code first I get the instanceID via getInstanceId() and this is working because I see the log statements.
But the Firestore database is never executed. I don't see any data in my database and the both methods are not called either.
No error message in the log.
I don't get it what's the problem here without any error message :-(
FirebaseInstanceId.getInstance().getInstanceId().addOnSuccessListener(instanceIdResult -> {
if(instanceIdResult == null) {
Log.e(TAG, "Firebase Instance Id Result is null!");
HyperLog.e(TAG, "Firebase Instance Id Result is null!");
return;
}
String mToken = instanceIdResult.getToken();
HyperLog.e(TAG, mToken);
Log.e(TAG,mToken);
Log.e(TAG,"ID is" + instanceIdResult.getId());
db.collection(C_USERS).document(eMail).collection(C_DEVICES).document(instanceIdResult.getId())
.set(deviceInfo)
.addOnSuccessListener(aVoid -> {
Log.e(TAG, "Success!");
callBack.onAddUpdateTokenSuccess();
})
.addOnFailureListener(e -> {
//noinspection Convert2MethodRef
Log.e(TAG, "Failure!");
callBack.onAddUpdateTokenFailure(e);
});
I test this on a real device with debug build and this device has internet (Mobile and WiFi).
Seems the problem is a not allowed API in the Google Cloud Console.
After digging deeper into the logs I have seen that "FireStore" writes this line:
Requests to this API securetoken.googleapis.com method google.identity.securetoken.v1.SecureToken.GrantToken are blocked.
Now I have added Token Service API to the allowed API's and it is working.
Both callbacks are now called successfully and the document is also written.
Please check that your API is allowed or not in the Google CLoud Console

Google plus profile pic url is not getting

In my android app there is google plus login button.Google plus login works fine in my app. I use this code to access url of google plus profile pic
String profileurl=Account.getPhotoUrl().toString();
When I use this code.I got errors caused by this reason
Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'java.lang.String android.net.Uri.toString()' on a null object reference
What should I do to get profile picture url of google plus account?
As the error message clearly states, you are invoking the method "toString()" on a null object, you can either change your code to catch null instances
if (Account.getPhotoUrl() != null){
String profileurl=Account.getPhotoUrl().toString();
}
or make sure that "getPhotoURL()" never returns null
It seems your Account is null and you are trying to access value on null object thats why you are getting null pointer exception. So please try to get like this
GoogleSignInResult result;// its your google result
GoogleSignInAccount acct = result.getSignInAccount();// here your Account value is null
String profileURL = "";
if (acct != null)
profileURL = acct.getPhotoUrl().toString();
You can try this with firebase.
https://firebase.google.com/docs/auth/android/google-signin

Check android purchase status but return the purchase token was not found

I refered google play android api to check the purchase and consumption status of an in-app item.
For some orders, I can get right result,but some return the error as below:
error: {
errors: [
{
domain: "global",
reason: "purchaseTokenNotFound",
message: "The purchase token was not found.",
locationType: "parameter",
location: "token"
}
],
code: 404,
message: "The purchase token was not found."
}
Purchase token is provided by google, does it can be faked?
I found if I cancel the google order, then check the purchase status,it will return the purchase token was not found. if not, i will get the right purchase status.
Hope somebody can help.
If you are selling the same INAPP product to the same user muliple times within a short period, then it's very likely that all access tokens except the last purchase will return a 404 code.
For example:
john#example.com went to your app and purchased com.example.test.product a few times, you will probaly notice within your records (or Google Wallet Merchant account) that it's the same user buying the product.
When you go to check the last purchase from this user, then the following is likely to appear
{
kind: "androidpublisher#inappPurchase",
purchaseTime: "1409823171827",
purchaseState: "0",
consumptionState: "1",
developerPayload: "My Product | Ref | 1409823162466"
}
and yet if you were to check his previous tokens, then it's very likely that his purchases will return 404!
I had read somewhere (can't remember where) that the purchase token created for each purchase is basically based on the inapp product and google user. Therefore, it's very likely that each purchase will "destroy" any previous purchase token created for the same user.
Hope this explanation helps. I am constantly having this problem everyday when my server is attempting to connect to the Google API and check the transactions. Perhaps one day somebody will read this and provide a solution :)
The documents are misleading. You don't need to use this API to verify purchases.
Mobile app have INAPP_PURCHASE_DATA and INAPP_DATA_SIGNATURE from getBuyIntent method.
You can verify the purchase with the signature and your public key.
https://developer.android.com/google/play/billing/billing_reference.html#getBuyIntent
You can find the public key on Google Play Developer Console -> YOUR_APP -> service and API
package main
import (
"crypto"
"crypto/rsa"
"crypto/sha1"
"crypto/x509"
"encoding/base64"
"encoding/pem"
"fmt"
)
//replace const below with your own.
const (
pubKeyPEM=`-----BEGIN PUBLIC KEY-----
Some thing like this
-----END PUBLIC KEY-----`
data = `purchase data from getBuyIntent API`
sign = `purchase data signature from getBuyIntent API`
)
func Panic(err error) {
if err != nil {
panic(err)
}
}
func main() {
PEMBlock, _ := pem.Decode([]byte(pubKeyPEM))
if PEMBlock == nil {
Panic(fmt.Errorf("Could not parse Public Key PEM"))
}
if PEMBlock.Type != "PUBLIC KEY" {
Panic(fmt.Errorf("Found wrong key type"))
}
pubkey, err := x509.ParsePKIXPublicKey(PEMBlock.Bytes)
if err != nil {
Panic(err)
}
// compute the sha1
h := sha1.New()
h.Write([]byte(data))
// decode b64 signature
signature, err := base64.StdEncoding.DecodeString(sign)
Panic(err)
// Verify
err = rsa.VerifyPKCS1v15(pubkey.(*rsa.PublicKey), crypto.SHA1, h.Sum(nil), signature)
Panic(err)
// It verified!
fmt.Println("OK")
}

re-install paid subscription on new Android device

I have an inapp subscription. I am trying to insure the re-installation of the app on the same or a new will recognize that the user has a valid subscription. The "already owned" response is supposed to have a value of "7", which works fine for consumable, managed products. For subscriptions, however, I do not get a "7" response. The messages are different, too. For a managed, consumable product the message is "Item already owned" with a "7" response. For subscriptions the message is "You already own this item", with NO "7" response, and the IAB result is "-1005:User cancelled". The subscription is active in Google Wallet, has not been cancelled. I get the response, I believe, from the alert box dismissal.
The question is, how do I recognize this response to the IABsetup? I have tried if request.mResponse = 1, but that does not work. I aparently do not get a useful response code for subscriptions. During testing, I have to turn off debug to upload the .apk so this is even more difficult to follow.
Why would the subscription response from the server differ from the managed product response for already owned items?
I need to be able to activate the app based on the already owned response.
Thanks.
I discovered the IabHelper.java has this:
else if (resultCode == Activity.RESULT_CANCELED) {
logDebug("Purchase canceled - Response: " + getResponseDesc(responseCode));
result = new IabResult(IABHELPER_USER_CANCELED, "User canceled.");
if (mPurchaseListener != null) mPurchaseListener.onIabPurchaseFinished(result, null);
}
I changed to this:
else if (resultCode == Activity.RESULT_CANCELED) {
logDebug("Purchase canceled - Response: " + getResponseDesc(responseCode));
result = new IabResult(responseCode, "User canceled.");
if (mPurchaseListener != null) mPurchaseListener.onIabPurchaseFinished(result, null);
}
Note the change from (IABHELPER_USER_CANCELED, "User canceled.") to (responseCode, "User Canceled")
Now the responseCode is passing to the
public void onIabPurchaseFinished(IabResult result, Purchase info)
so I can determine if the response is a dialog cancel and allow the active subscription to re-install and contact my server. At that point I am doing the 0Auth API call to Google to verify the installation and active subscription.
There may be alternate ways to do this, but this worked.
Hope this helps the 3 people in the world who are doing Android inapp subscriptions.

android in app billing purchase verification failed

i' having trouble implementing in app billing in my android app.
i'm getting a purchase signature verification failed.
In a first time i tough it was the base64 key but i checked it many times and i'm still getting the error, then after i took a look at the Security.java file and i found this method which i edited for get some informations about what was wrong:
public static boolean verifyPurchase(String base64PublicKey, String signedData, String signature) {
if (TextUtils.isEmpty(signedData) || TextUtils.isEmpty(base64PublicKey) ||
TextUtils.isEmpty(signature)) {
if(TextUtils.isEmpty(signedData)) Log.d(TAG, "SIGNED DATA EMPTY");
if(TextUtils.isEmpty(base64PublicKey)) Log.d(TAG, "KEY IS EMPTY");
if(TextUtils.isEmpty(signature)) Log.d(TAG, "SIGNATURE IS EMPTY");
Log.e(TAG, "Purchase verification failed: missing data.");
return false;
}
PublicKey key = Security.generatePublicKey(base64PublicKey);
return Security.verify(key, signedData, signature);
}
And i'm getting "signature is empty".
Even after i follow the steps below:
-Sign the apk with my release key
-upload it as a draft
-install it on a device with "adb -d install app.apk"
I'm testing with real purchases.
Thanks.
Edit The purchase flow is fine, i get the error when i call queryInventoryAsync
You can use the test SKU's to do testing, as explained here. These are:
android.test.purchased
android.test.canceled
android.test.refunded
android.test.item_unavailable
These purchases will be successful (at least the android.test.purchased) even in test and debug scenario's, without the need to cancel the purchase.
In the verifyPurchase I changed return false to:
Log.e(TAG, "Purchase verification failed: missing data.");
if (BuildConfig.DEBUG) {
return true;
}
return false;
but you should be aware to use this only in test scenario's.
This will return true, if you have a debug build, and the signature data is missing. Since the BuildConfig.DEBUG will be false in a production build this should be OK. But better is to remove this code after everything is debugged.
Replace your verifyPurchase() method with below one. Use old code that given below, google developer are trying to solve this error in the near future but before they updated their code you should prefer below code.
public static boolean verifyPurchase(String base64PublicKey, String signedData, String signature) {
if (signedData == null) {
Log.e(TAG, "data is null");
return false;
}
boolean verified = false;
if (!TextUtils.isEmpty(signature)) {
PublicKey key = Security.generatePublicKey(base64PublicKey);
verified = Security.verify(key, signedData, signature);
if (!verified) {
Log.w(TAG, "signature does not match data.");
return false;
}
}
return true;
}
check this link for more information:
In App billing not working after update - Google Store
Use try to replace OLD CODE method verifyPurchase() method in your project. But It should be only happens when you are trying to purchase test products. Let me know for the real products purchase also after using this code.
Edit:
Why it happens because we will not get any signature while we are using dummy product like "android.test.purchased". So in the old code it is working good because we were return true even if signature is not given and for the New code we are returning false.
more information about the signature data null or blank from link1 and link2
So I suggest you just replace old code method verifyPurchase() instead of New Code method.
I think may be New Code will work fine for the real product but not in the dummy product. But yet I have not tested for the real product.
or
use GvS's answer for the test purchases it also the good solution for the new code.
Hope it will solve your problem.
Make sure that you are logged in with the right user on your phone or e.g. add your phone's google account as a test user in the developer console.
http://developer.android.com/google/play/billing/billing_testing.html#billing-testing-static:
In some cases, the reserved items may return signed static responses, which lets you test signature verification in your application. The reserved items only return signed responses if the user running the application has a developer or test account.
set return value to true In
public static boolean verifyPurchase(String base64PublicKey, String signedData, String signature) {
return true;
}
after tesing undo the change

Categories

Resources