Skip to content

Commit 3a25045

Browse files
committed
Merge branch 'Unic8-master'
2 parents d464c4e + 0776e41 commit 3a25045

8 files changed

+80
-31
lines changed

README.md

+4
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,10 @@ As a result you will get a `TransactionDetails` object with the following info i
159159
public final String orderId;
160160
public final String purchaseToken;
161161
public final Date purchaseTime;
162+
163+
// containing the raw json string from google play and the signature to
164+
// verify the purchase on your own server
165+
public final PurchaseInfo purchaseInfo;
162166
```
163167

164168
## License

library/AndroidManifest.xml

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
33
package="com.anjlab.android.iab.v3"
44
android:versionCode="1"
5-
android:versionName="1.0.9">
5+
android:versionName="1.0.11">
66

77
<uses-sdk
88
android:minSdkVersion="8"

library/build.gradle

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ apply plugin: 'maven'
33
apply plugin: 'signing'
44

55
group 'com.anjlab.android.iab.v3'
6-
version '1.0.10'
6+
version '1.0.11'
77

88
android {
99
compileSdkVersion 8

library/library.iml

+4-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
<?xml version="1.0" encoding="UTF-8"?>
2-
<module external.linked.project.path="$MODULE_DIR$" external.root.project.path="$MODULE_DIR$/.." external.system.id="GRADLE" external.system.module.group="com.anjlab.android.iab.v3" external.system.module.version="1.0.10" type="JAVA_MODULE" version="4">
2+
<module external.linked.project.path="$MODULE_DIR$" external.root.project.path="$MODULE_DIR$/.." external.system.id="GRADLE" external.system.module.group="com.anjlab.android.iab.v3" external.system.module.version="1.0.11" type="JAVA_MODULE" version="4">
33
<component name="FacetManager">
44
<facet type="android-gradle" name="Android-Gradle">
55
<configuration>
@@ -71,7 +71,10 @@
7171
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/res" />
7272
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/rs" />
7373
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/symbols" />
74+
<excludeFolder url="file://$MODULE_DIR$/build/libs" />
7475
<excludeFolder url="file://$MODULE_DIR$/build/outputs" />
76+
<excludeFolder url="file://$MODULE_DIR$/build/poms" />
77+
<excludeFolder url="file://$MODULE_DIR$/build/tmp" />
7578
</content>
7679
<orderEntry type="jdk" jdkName="Android API 8 Platform" jdkType="Android SDK" />
7780
<orderEntry type="sourceFolder" forTests="false" />

library/src/com/anjlab/android/iab/v3/BillingCache.java

+10-8
Original file line numberDiff line numberDiff line change
@@ -27,12 +27,12 @@ class BillingCache extends BillingBase {
2727
private static final String ENTRY_DELIMITER = "#####";
2828
private static final String LINE_DELIMITER = ">>>>>";
2929

30-
private HashMap<String, String> data;
30+
private HashMap<String, PurchaseInfo> data;
3131
private String cacheKey;
3232

3333
public BillingCache(Activity context, String key) {
3434
super(context);
35-
data = new HashMap<String, String>();
35+
data = new HashMap<String, PurchaseInfo>();
3636
cacheKey = key;
3737
load();
3838
}
@@ -46,29 +46,31 @@ private void load() {
4646
if (!TextUtils.isEmpty(entry)) {
4747
String[] parts = entry.split(Pattern.quote(LINE_DELIMITER));
4848
if (parts.length > 1)
49-
data.put(parts[0], parts[1]);
49+
data.put(parts[0], new PurchaseInfo(parts[1], parts[2]));
5050
}
5151
}
5252
}
5353

5454
private void flush() {
5555
ArrayList<String> output = new ArrayList<String>();
56-
for(String productId : data.keySet())
57-
output.add(productId + LINE_DELIMITER + data.get(productId));
56+
for(String productId : data.keySet()) {
57+
PurchaseInfo info = data.get(productId);
58+
output.add(productId + LINE_DELIMITER + info.responseData + LINE_DELIMITER + info.signature);
59+
}
5860
saveString(getPreferencesCacheKey(), TextUtils.join(ENTRY_DELIMITER, output));
5961
}
6062

6163
public boolean includesProduct(String productId) {
6264
return data != null && data.containsKey(productId);
6365
}
6466

65-
public String getDetails(String productId) {
67+
public PurchaseInfo getDetails(String productId) {
6668
return data.containsKey(productId) ? data.get(productId) : null;
6769
}
6870

69-
public void put(String productId, String details) {
71+
public void put(String productId, String details, String signature) {
7072
if (!data.containsKey(productId)) {
71-
data.put(productId, details);
73+
data.put(productId, new PurchaseInfo(details, signature));
7274
flush();
7375
}
7476
}

library/src/com/anjlab/android/iab/v3/BillingProcessor.java

+19-16
Original file line numberDiff line numberDiff line change
@@ -15,13 +15,6 @@
1515
*/
1616
package com.anjlab.android.iab.v3;
1717

18-
import java.util.ArrayList;
19-
import java.util.List;
20-
import java.util.UUID;
21-
22-
import org.json.JSONException;
23-
import org.json.JSONObject;
24-
2518
import android.app.Activity;
2619
import android.app.PendingIntent;
2720
import android.content.ComponentName;
@@ -35,6 +28,13 @@
3528

3629
import com.android.vending.billing.IInAppBillingService;
3730

31+
import org.json.JSONException;
32+
import org.json.JSONObject;
33+
34+
import java.util.ArrayList;
35+
import java.util.List;
36+
import java.util.UUID;
37+
3838
public class BillingProcessor extends BillingBase {
3939

4040
/**
@@ -50,7 +50,7 @@ public static interface IBillingHandler {
5050

5151
private static final int PURCHASE_FLOW_REQUEST_CODE = 2061984;
5252
private static final String LOG_TAG = "iabv3";
53-
private static final String SETTINGS_VERSION = ".v2_5";
53+
private static final String SETTINGS_VERSION = ".v2_6";
5454
private static final String RESTORE_KEY = ".products.restored" + SETTINGS_VERSION;
5555
private static final String MANAGED_PRODUCTS_CACHE_KEY = ".products.cache" + SETTINGS_VERSION;
5656
private static final String SUBSCRIPTIONS_CACHE_KEY = ".subscriptions.cache" + SETTINGS_VERSION;
@@ -143,9 +143,12 @@ private boolean loadPurchasesByType(String type, BillingCache cacheStorage) {
143143
Bundle bundle = billingService.getPurchases(Constants.GOOGLE_API_VERSION, contextPackageName, type, null);
144144
if (bundle.getInt(Constants.RESPONSE_CODE) == Constants.BILLING_RESPONSE_RESULT_OK) {
145145
cacheStorage.clear();
146-
for (String purchaseData : bundle.getStringArrayList(Constants.INAPP_PURCHASE_DATA_LIST)) {
147-
JSONObject purchase = new JSONObject(purchaseData);
148-
cacheStorage.put(purchase.getString(Constants.RESPONSE_PRODUCT_ID), purchaseData);
146+
ArrayList<String> purchaseList = bundle.getStringArrayList(Constants.INAPP_PURCHASE_DATA_LIST);
147+
ArrayList<String> signatureList = bundle.getStringArrayList(Constants.RESPONSE_INAPP_SIGNATURE);
148+
for (int i=0; i<purchaseList.size(); i++) {
149+
String jsonData = purchaseList.get(i);
150+
JSONObject purchase = new JSONObject(jsonData);
151+
cacheStorage.put(purchase.getString(Constants.RESPONSE_PRODUCT_ID), jsonData, signatureList.get(i));
149152
}
150153
}
151154
return true;
@@ -210,10 +213,10 @@ else if (response == Constants.BILLING_RESPONSE_RESULT_ITEM_ALREADY_OWNED) {
210213
}
211214

212215
private TransactionDetails getPurchaseTransactionDetails(String productId, BillingCache cache) {
213-
String details = cache.getDetails(productId);
214-
if (!TextUtils.isEmpty(details)) {
216+
PurchaseInfo details = cache.getDetails(productId);
217+
if (details != null && !TextUtils.isEmpty(details.responseData)) {
215218
try {
216-
return new TransactionDetails(new JSONObject(details));
219+
return new TransactionDetails(details);
217220
} catch (JSONException e) {
218221
Log.e(LOG_TAG, "Failed to load saved purchase details for " + productId);
219222
}
@@ -308,9 +311,9 @@ public boolean handleActivityResult(int requestCode, int resultCode, Intent data
308311
if (purchasePayload.equals(developerPayload)) {
309312
if (verifyPurchaseSignature(purchaseData, dataSignature)) {
310313
BillingCache cache = purchasedSubscription ? cachedSubscriptions : cachedProducts;
311-
cache.put(productId, purchaseData);
314+
cache.put(productId, purchaseData, dataSignature);
312315
if(eventHandler != null)
313-
eventHandler.onProductPurchased(productId, new TransactionDetails(purchase));
316+
eventHandler.onProductPurchased(productId, new TransactionDetails(new PurchaseInfo(purchaseData, dataSignature)));
314317
}
315318
else {
316319
Log.e(LOG_TAG, "Public key signature doesn't match!");
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
/**
2+
* Copyright 2014 AnjLab and Unic8
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package com.anjlab.android.iab.v3;
18+
19+
/**
20+
* With this PurchaseInfo a developer is able verify
21+
* a purchase from the google play store on his own
22+
* server. An example implementation of how to verify
23+
* a purchase you can find <a href="https://github.com/mgoldsborough/google-play-in-app-billing-verification/blob/master/library/GooglePlay/InAppBilling/GooglePlayResponseValidator.php#L64">here</a>
24+
*
25+
*/
26+
public class PurchaseInfo {
27+
28+
public final String responseData;
29+
30+
public final String signature;
31+
32+
PurchaseInfo(String responseData, String signature) {
33+
this.responseData = responseData;
34+
this.signature = signature;
35+
}
36+
}

library/src/com/anjlab/android/iab/v3/TransactionDetails.java

+5-4
Original file line numberDiff line numberDiff line change
@@ -30,10 +30,11 @@ public class TransactionDetails {
3030

3131
public final Date purchaseTime;
3232

33-
public final JSONObject rawJSONObject;
33+
public final PurchaseInfo purchaseInfo;
3434

35-
public TransactionDetails(JSONObject source) throws JSONException {
36-
rawJSONObject = source;
35+
public TransactionDetails(PurchaseInfo info) throws JSONException {
36+
JSONObject source = new JSONObject(info.responseData);
37+
purchaseInfo = info;
3738
productId = source.getString(Constants.RESPONSE_PRODUCT_ID);
3839
orderId = source.getString(Constants.RESPONSE_ORDER_ID);
3940
purchaseToken = source.getString(Constants.RESPONSE_PURCHASE_TOKEN);
@@ -42,6 +43,6 @@ public TransactionDetails(JSONObject source) throws JSONException {
4243

4344
@Override
4445
public String toString() {
45-
return String.format("%s purchased at %s(%s). Token: %s", productId, purchaseTime, orderId, purchaseToken);
46+
return String.format("%s purchased at %s(%s). Token: %s, Signature: %s", productId, purchaseTime, orderId, purchaseToken, purchaseInfo.signature);
4647
}
4748
}

0 commit comments

Comments
 (0)