Gilli Danda v1.1.5版本的 MD5 值为:bcf5cb835fbff288fa65b9651dd21e30
以下内容为反编译后的 IabHelper.java 源代码,内容仅作参考
package com.unity.purchasing.googleplay;
import android.app.Activity;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.content.IntentSender;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.os.RemoteException;
import android.text.TextUtils;
import android.util.Log;
import com.android.vending.billing.IInAppBillingService;
import com.google.vr.ndk.base.DaydreamApi;
import com.unity.purchasing.common.SaneJSONObject;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import org.json.JSONException;
public class IabHelper {
public static final int BILLING_RESPONSE_RESULT_BILLING_UNAVAILABLE = 3;
public static final int BILLING_RESPONSE_RESULT_DEVELOPER_ERROR = 5;
public static final int BILLING_RESPONSE_RESULT_ERROR = 6;
public static final int BILLING_RESPONSE_RESULT_ITEM_ALREADY_OWNED = 7;
public static final int BILLING_RESPONSE_RESULT_ITEM_NOT_OWNED = 8;
public static final int BILLING_RESPONSE_RESULT_ITEM_UNAVAILABLE = 4;
public static final int BILLING_RESPONSE_RESULT_OK = 0;
public static final int BILLING_RESPONSE_RESULT_SERVICE_UNAVAILABLE = 2;
public static final int BILLING_RESPONSE_RESULT_USER_CANCELED = 1;
public static final String GET_SKU_DETAILS_ITEM_LIST = "ITEM_ID_LIST";
public static final String GET_SKU_DETAILS_ITEM_TYPE_LIST = "ITEM_TYPE_LIST";
public static final int IABHELPER_BAD_RESPONSE = -1002;
public static final int IABHELPER_ERROR_BASE = -1000;
public static final int IABHELPER_INVALID_CONSUMPTION = -1010;
public static final int IABHELPER_MISSING_TOKEN = -1007;
public static final int IABHELPER_REMOTE_EXCEPTION = -1001;
public static final int IABHELPER_SEND_INTENT_FAILED = -1004;
public static final int IABHELPER_SUBSCRIPTIONS_NOT_AVAILABLE = -1009;
public static final int IABHELPER_UNKNOWN_ERROR = -1008;
public static final int IABHELPER_UNKNOWN_PURCHASE_RESPONSE = -1006;
public static final int IABHELPER_USER_CANCELLED = -1005;
public static final int IABHELPER_VERIFICATION_FAILED = -1003;
public static final String INAPP_CONTINUATION_TOKEN = "INAPP_CONTINUATION_TOKEN";
public static final String ITEM_TYPE_INAPP = "inapp";
public static final String ITEM_TYPE_SUBS = "subs";
public static final String RESPONSE_BUY_INTENT = "BUY_INTENT";
public static final String RESPONSE_CODE = "RESPONSE_CODE";
public static final String RESPONSE_GET_SKU_DETAILS_LIST = "DETAILS_LIST";
public static final String RESPONSE_INAPP_ITEM_LIST = "INAPP_PURCHASE_ITEM_LIST";
public static final String RESPONSE_INAPP_PURCHASE_DATA = "INAPP_PURCHASE_DATA";
public static final String RESPONSE_INAPP_PURCHASE_DATA_LIST = "INAPP_PURCHASE_DATA_LIST";
public static final String RESPONSE_INAPP_SIGNATURE = "INAPP_DATA_SIGNATURE";
public static final String RESPONSE_INAPP_SIGNATURE_LIST = "INAPP_DATA_SIGNATURE_LIST";
public static HashMap<Integer, String> billingResponseCodeNames = new HashMap<>();
private IActivityLauncher launcher;
Context mContext;
OnIabPurchaseFinishedListener mPurchaseListener;
String mPurchasingItemType;
int mRequestCode;
private IBillingServiceManager serviceManager;
boolean mDebugLog = false;
String mDebugTag = "IabHelper";
volatile boolean mSetupDone = false;
volatile boolean mDisposed = false;
boolean mSubscriptionsSupported = false;
boolean mSubscriptionPurchaseHistorySupported = false;
private boolean mVrSupported = false;
private boolean mUnityVrEnabled = false;
private boolean mDaydreamApiAvailable = false;
String mAsyncOperation = "";
private Inventory inv = new Inventory();
public interface OnConsumeFinishedListener {
void onConsumeFinished(Purchase purchase, IabResult iabResult) throws JSONException;
}
public interface OnConsumeMultiFinishedListener {
void onConsumeMultiFinished(List<Purchase> list, List<IabResult> list2);
}
public interface OnIabPurchaseFinishedListener {
void onIabPurchaseFinished(IabResult iabResult, Purchase purchase);
}
public interface OnIabSetupFinishedListener {
void onIabSetupFinished(IabResult iabResult);
}
public interface QueryInventoryFinishedListener {
void onQueryInventoryFinished(IabResult iabResult, Inventory inventory) throws Exception;
}
static {
billingResponseCodeNames.put(0, "BILLING_RESPONSE_RESULT_OK");
billingResponseCodeNames.put(1, "BILLING_RESPONSE_RESULT_USER_CANCELED");
billingResponseCodeNames.put(2, "BILLING_RESPONSE_RESULT_SERVICE_UNAVAILABLE");
billingResponseCodeNames.put(3, "BILLING_RESPONSE_RESULT_BILLING_UNAVAILABLE");
billingResponseCodeNames.put(4, "BILLING_RESPONSE_RESULT_ITEM_UNAVAILABLE");
billingResponseCodeNames.put(5, "BILLING_RESPONSE_RESULT_DEVELOPER_ERROR");
billingResponseCodeNames.put(6, "BILLING_RESPONSE_RESULT_ERROR");
billingResponseCodeNames.put(7, "BILLING_RESPONSE_RESULT_ITEM_ALREADY_OWNED");
billingResponseCodeNames.put(8, "BILLING_RESPONSE_RESULT_ITEM_NOT_OWNED");
billingResponseCodeNames.put(-1000, "IABHELPER_ERROR_BASE");
billingResponseCodeNames.put(Integer.valueOf(IABHELPER_REMOTE_EXCEPTION), "IABHELPER_REMOTE_EXCEPTION");
billingResponseCodeNames.put(Integer.valueOf(IABHELPER_BAD_RESPONSE), "IABHELPER_BAD_RESPONSE");
billingResponseCodeNames.put(Integer.valueOf(IABHELPER_VERIFICATION_FAILED), "IABHELPER_VERIFICATION_FAILED");
billingResponseCodeNames.put(Integer.valueOf(IABHELPER_SEND_INTENT_FAILED), "IABHELPER_SEND_INTENT_FAILED");
billingResponseCodeNames.put(Integer.valueOf(IABHELPER_USER_CANCELLED), "IABHELPER_USER_CANCELLED");
billingResponseCodeNames.put(Integer.valueOf(IABHELPER_UNKNOWN_PURCHASE_RESPONSE), "IABHELPER_UNKNOWN_PURCHASE_RESPONSE");
billingResponseCodeNames.put(Integer.valueOf(IABHELPER_MISSING_TOKEN), "IABHELPER_MISSING_TOKEN");
billingResponseCodeNames.put(Integer.valueOf(IABHELPER_UNKNOWN_ERROR), "IABHELPER_UNKNOWN_ERROR");
billingResponseCodeNames.put(Integer.valueOf(IABHELPER_SUBSCRIPTIONS_NOT_AVAILABLE), "IABHELPER_SUBSCRIPTIONS_NOT_AVAILABLE");
billingResponseCodeNames.put(Integer.valueOf(IABHELPER_INVALID_CONSUMPTION), "IABHELPER_INVALID_CONSUMPTION");
}
public IabHelper(Context ctx, IBillingServiceManager manager, IActivityLauncher launcher) {
this.mContext = ctx.getApplicationContext();
this.serviceManager = manager;
this.launcher = launcher;
logDebug("IAB helper created.");
}
public void enableDebugLogging(boolean enable, String tag) {
this.mDebugLog = enable;
this.mDebugTag = tag;
}
public void enableDebugLogging(boolean enable) {
this.mDebugLog = enable;
}
public void enableUnityVr(boolean enabled) {
this.mUnityVrEnabled = enabled;
}
public void enableDaydreamApi(boolean enabled) {
this.mDaydreamApiAvailable = enabled;
}
public void startSetup(final OnIabSetupFinishedListener listener) {
if (this.mSetupDone) {
throw new IllegalStateException("IAB helper is already set up.");
}
logDebug("Starting in-app billing setup.");
this.serviceManager.workWith(new BillingServiceProcessor() {
@Override
public void workWith(IInAppBillingService service) {
IabHelper.this.finishSetup(listener, service);
}
});
}
public void finishSetup(OnIabSetupFinishedListener listener, IInAppBillingService service) {
String packageName = this.mContext.getPackageName();
try {
logDebug("Checking for in-app billing 3 support.");
int response = service.isBillingSupported(3, packageName, "inapp");
if (response != 0) {
listener.onIabSetupFinished(new IabResult(response, "Billing V3 not supported."));
this.mSubscriptionsSupported = false;
return;
}
logDebug("In-app billing version 3 supported for " + packageName);
int response2 = service.isBillingSupported(3, packageName, "subs");
if (response2 == 0) {
logDebug("Subscriptions AVAILABLE.");
this.mSubscriptionsSupported = true;
int response_v6 = service.isBillingSupported(6, packageName, "subs");
if (response_v6 == 0) {
this.mSubscriptionPurchaseHistorySupported = true;
logDebug("Subscriptions information parse AVAILABLE.");
} else {
logDebug("Subscriptions information parse NOT AVAILABLE.");
}
} else {
logDebug("Subscriptions NOT AVAILABLE. Response: " + response2);
}
Bundle bundle = new Bundle();
bundle.putBoolean("vr", true);
int response3 = service.isBillingSupportedExtraParams(7, this.mContext.getPackageName(), "inapp", bundle);
if (response3 == 0) {
logDebug("VR supported.");
this.mVrSupported = true;
} else {
logDebug("VR purchases NOT AVAILABLE. Response: " + response3);
}
this.mSetupDone = true;
listener.onIabSetupFinished(new IabResult(0, "Setup successful."));
} catch (RemoteException e) {
listener.onIabSetupFinished(new IabResult(IABHELPER_REMOTE_EXCEPTION, "RemoteException while setting up in-app billing."));
}
}
public void dispose() {
logDebug("Disposing.");
this.mSetupDone = false;
this.serviceManager.dispose();
this.mDisposed = true;
}
public boolean subscriptionsSupported() {
return this.mSubscriptionsSupported;
}
public boolean subscriptionPurchaseHistorySupported() {
return this.mSubscriptionPurchaseHistorySupported;
}
public void launchPurchaseFlow(Activity act, String sku, int requestCode, OnIabPurchaseFinishedListener listener) {
launchPurchaseFlow(act, sku, requestCode, listener, "");
}
public void launchPurchaseFlow(Activity act, String sku, int requestCode, OnIabPurchaseFinishedListener listener, String extraData) {
launchPurchaseFlow(act, sku, "inapp", requestCode, listener, extraData);
}
public void launchSubscriptionPurchaseFlow(Activity act, String sku, int requestCode, OnIabPurchaseFinishedListener listener) {
launchSubscriptionPurchaseFlow(act, sku, requestCode, listener, "");
}
public void launchSubscriptionPurchaseFlow(Activity act, String sku, int requestCode, OnIabPurchaseFinishedListener listener, String extraData) {
launchPurchaseFlow(act, sku, "subs", requestCode, listener, extraData);
}
public void launchPurchaseFlow(final Activity act, final String sku, final String itemType, final int requestCode, final OnIabPurchaseFinishedListener listener, final String extraData) {
checkSetupDone("launchPurchaseFlow");
if (itemType.equals("subs") && !this.mSubscriptionsSupported) {
IabResult r = new IabResult(IABHELPER_SUBSCRIPTIONS_NOT_AVAILABLE, "Subscriptions are not available.");
if (listener != null) {
listener.onIabPurchaseFinished(r, null);
return;
}
return;
}
this.serviceManager.workWith(new BillingServiceProcessor() {
@Override
public void workWith(IInAppBillingService service) {
Bundle buyIntentBundle;
Purchase purchase;
try {
IabHelper.this.logDebug("Constructing buy intent for " + sku + ", item type: " + itemType);
if (IabHelper.this.mVrSupported && IabHelper.this.mUnityVrEnabled) {
Bundle bundle = new Bundle();
bundle.putBoolean("vr", true);
IabHelper.this.logDebug("Initiating VR purchase intent");
buyIntentBundle = service.getBuyIntentExtraParams(7, IabHelper.this.mContext.getPackageName(), sku, itemType, extraData, bundle);
} else {
buyIntentBundle = service.getBuyIntent(3, IabHelper.this.mContext.getPackageName(), sku, itemType, extraData);
}
int response = IabHelper.this.getResponseCodeFromBundle(buyIntentBundle);
if (response != 0) {
IabHelper.this.logError("Unable to buy item, Error response: " + IabHelper.getResponseDesc(response));
IabResult result = new IabResult(response, "Unable to buy item");
SaneJSONObject o = new SaneJSONObject();
o.put("productId", sku);
if (response == 7) {
try {
if (IabHelper.this.inv.hasPurchase(sku)) {
purchase = IabHelper.this.inv.getPurchase(sku);
act.finish();
if (listener == null) {
listener.onIabPurchaseFinished(result, purchase);
return;
}
return;
}
} catch (JSONException e) {
e.printStackTrace();
return;
}
}
purchase = new Purchase(itemType, o.toString(), "");
act.finish();
if (listener == null) {
}
} else {
final PendingIntent pendingIntent = (PendingIntent) buyIntentBundle.getParcelable(IabHelper.RESPONSE_BUY_INTENT);
IabHelper.this.logDebug("Launching buy intent for " + sku + ". Request code: " + requestCode);
IabHelper.this.mRequestCode = requestCode;
IabHelper.this.mPurchaseListener = listener;
IabHelper.this.mPurchasingItemType = itemType;
if (IabHelper.this.mVrSupported && IabHelper.this.mUnityVrEnabled && IabHelper.this.mDaydreamApiAvailable) {
Runnable task = new Runnable() {
@Override
public void run() {
DaydreamApi api = DaydreamApi.create(act);
api.launchInVrForResult(act, pendingIntent, requestCode);
api.close();
}
};
new Handler(Looper.getMainLooper()).post(task);
} else {
pendingIntent.getIntentSender();
IabHelper.this.launcher.startIntentSenderForResult(act, pendingIntent, requestCode, new Intent(), sku);
}
}
} catch (IntentSender.SendIntentException e2) {
IabHelper.this.logError("SendIntentException while launching purchase flow for sku " + sku);
e2.printStackTrace();
IabResult result2 = new IabResult(IabHelper.IABHELPER_SEND_INTENT_FAILED, "Failed to send intent.");
if (listener != null) {
listener.onIabPurchaseFinished(result2, null);
}
} catch (RemoteException e3) {
IabHelper.this.logError("RemoteException while launching purchase flow for sku " + sku);
e3.printStackTrace();
IabResult result3 = new IabResult(IabHelper.IABHELPER_REMOTE_EXCEPTION, "Remote exception while starting purchase flow");
if (listener != null) {
listener.onIabPurchaseFinished(result3, null);
}
}
}
});
}
public boolean handleActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode != this.mRequestCode) {
return false;
}
checkSetupDone("handleActivityResult");
if (data == null) {
logError("Null data in IAB activity result.");
IabResult result = new IabResult(IABHELPER_BAD_RESPONSE, "Null data in IAB result");
if (this.mPurchaseListener != null) {
this.mPurchaseListener.onIabPurchaseFinished(result, null);
}
return true;
}
int responseCode = getResponseCodeFromIntent(data);
String purchaseData = data.getStringExtra(RESPONSE_INAPP_PURCHASE_DATA);
String dataSignature = data.getStringExtra(RESPONSE_INAPP_SIGNATURE);
if (resultCode == -1 && responseCode == 0) {
logDebug("Successful resultcode from purchase activity.");
logDebug("Purchase data: " + purchaseData);
logDebug("Data signature: " + dataSignature);
logDebug("Extras: " + data.getExtras());
logDebug("Expected item type: " + this.mPurchasingItemType);
if (purchaseData == null || dataSignature == null) {
logError("BUG: either purchaseData or dataSignature is null.");
logDebug("Extras: " + data.getExtras().toString());
IabResult result2 = new IabResult(IABHELPER_UNKNOWN_ERROR, "IAB returned null purchaseData or dataSignature");
if (this.mPurchaseListener != null) {
this.mPurchaseListener.onIabPurchaseFinished(result2, null);
}
return true;
}
try {
Purchase purchase = new Purchase(this.mPurchasingItemType, purchaseData, dataSignature);
try {
purchase.getSku();
if (this.mPurchaseListener != null) {
this.mPurchaseListener.onIabPurchaseFinished(new IabResult(0, "Success"), purchase);
}
} catch (JSONException e) {
e = e;
logError("Failed to parse purchase data.");
e.printStackTrace();
IabResult result3 = new IabResult(IABHELPER_BAD_RESPONSE, "Failed to parse purchase data.");
if (this.mPurchaseListener != null) {
this.mPurchaseListener.onIabPurchaseFinished(result3, null);
}
return true;
}
} catch (JSONException e2) {
e = e2;
}
} else if (resultCode == -1) {
logDebug("Result code was OK but in-app billing response was not OK: " + getResponseDesc(responseCode));
if (this.mPurchaseListener != null) {
IabResult result4 = new IabResult(responseCode, "Problem purchasing item.");
this.mPurchaseListener.onIabPurchaseFinished(result4, null);
}
} else if (resultCode == 0) {
logDebug("Purchase canceled - Response: " + getResponseDesc(responseCode));
IabResult result5 = new IabResult(IABHELPER_USER_CANCELLED, "User canceled.");
if (this.mPurchaseListener != null) {
this.mPurchaseListener.onIabPurchaseFinished(result5, null);
}
} else {
logError("Purchase failed. Result code: " + Integer.toString(resultCode) + ". Response: " + getResponseDesc(responseCode));
IabResult result6 = new IabResult(IABHELPER_UNKNOWN_PURCHASE_RESPONSE, "Unknown purchase response.");
if (this.mPurchaseListener != null) {
this.mPurchaseListener.onIabPurchaseFinished(result6, null);
}
}
return true;
}
public Inventory queryInventory(boolean querySkuDetails, List<String> moreSkus, IInAppBillingService service) throws IabException {
return queryInventory(querySkuDetails, moreSkus, null, service);
}
public Inventory queryInventory(boolean querySkuDetails, List<String> moreItemSkus, List<String> moreSubsSkus, IInAppBillingService service) throws IabException {
int r;
int r2;
int r3;
checkSetupDone("queryInventory");
try {
int r4 = queryPurchases(this.inv, "inapp", service);
if (r4 != 0) {
throw new IabException(r4, "Error refreshing inventory (querying owned items).");
}
if (querySkuDetails && (r3 = querySkuDetails("inapp", this.inv, moreItemSkus, service)) != 0) {
throw new IabException(r3, "Error refreshing inventory (querying prices of items).");
}
if (this.mSubscriptionsSupported) {
int r5 = queryPurchases(this.inv, "subs", service);
if (r5 != 0) {
throw new IabException(r5, "Error refreshing inventory (querying owned subscriptions).");
}
if (querySkuDetails && (r2 = querySkuDetails("subs", this.inv, moreItemSkus, service)) != 0) {
throw new IabException(r2, "Error refreshing inventory (querying prices of subscriptions).");
}
}
if (this.mSubscriptionPurchaseHistorySupported && (r = queryPurchaseHistory(this.inv, "subs", service)) != 0) {
throw new IabException(r, "Error query Purchase History");
}
return this.inv;
} catch (RemoteException e) {
throw new IabException(IABHELPER_REMOTE_EXCEPTION, "Remote exception while refreshing inventory.", e);
} catch (SecurityException e2) {
throw new IabException(IABHELPER_UNKNOWN_ERROR, "SecurityException querying inventory, update Google Play - https://github.com/googlesamples/android-play-billing/issues/26", e2);
} catch (JSONException e3) {
throw new IabException(IABHELPER_BAD_RESPONSE, "Error parsing JSON response while refreshing inventory.", e3);
}
}
public void queryInventoryAsync(final boolean querySkuDetails, final List<String> moreSkus, final QueryInventoryFinishedListener listener, final long delay) {
checkSetupDone("queryInventory");
this.serviceManager.workWith(new BillingServiceProcessor() {
@Override
public void workWith(IInAppBillingService service) {
try {
Thread.sleep(delay);
} catch (InterruptedException e) {
}
IabResult result = new IabResult(0, "Inventory refresh successful.");
Inventory inv = null;
try {
inv = IabHelper.this.queryInventory(querySkuDetails, moreSkus, service);
} catch (IabException ex) {
result = ex.getResult();
}
IabResult result_f = result;
Inventory inv_f = inv;
if (!IabHelper.this.mDisposed && listener != null) {
try {
listener.onQueryInventoryFinished(result_f, inv_f);
} catch (Exception e2) {
e2.printStackTrace();
}
}
}
});
}
public void queryInventoryAsync(QueryInventoryFinishedListener listener) {
queryInventoryAsync(true, null, listener, 0L);
}
public void queryInventoryAsync(boolean querySkuDetails, QueryInventoryFinishedListener listener) {
queryInventoryAsync(querySkuDetails, null, listener, 0L);
}
void consume(Purchase itemInfo, IInAppBillingService service) throws IabException {
if (!itemInfo.mItemType.equals("inapp")) {
throw new IabException(IABHELPER_INVALID_CONSUMPTION, "Items of type '" + itemInfo.mItemType + "' can't be consumed.");
}
try {
String token = itemInfo.getToken();
String sku = itemInfo.getSku();
if (token == null || token.equals("")) {
logError("Can't consume " + sku + ". No token.");
throw new IabException(IABHELPER_MISSING_TOKEN, "PurchaseInfo is missing token for sku: " + sku + " " + itemInfo);
}
logDebug("Consuming sku: " + sku + ", token: " + token);
int response = service.consumePurchase(3, this.mContext.getPackageName(), token);
if (response == 0) {
logDebug("Successfully consumed sku: " + sku);
} else {
logDebug("Error consuming consuming sku " + sku + ". " + getResponseDesc(response));
throw new IabException(response, "Error consuming sku " + sku);
}
} catch (RemoteException e) {
throw new IabException(IABHELPER_REMOTE_EXCEPTION, "Remote exception while consuming. PurchaseInfo: " + itemInfo, e);
}
}
public void consumeAsync(Purchase purchase, OnConsumeFinishedListener listener) {
checkSetupDone("consume");
List<Purchase> purchases = new ArrayList<>();
purchases.add(purchase);
consumeAsyncInternal(purchases, listener, null);
}
public void consumeAsync(List<Purchase> purchases, OnConsumeMultiFinishedListener listener) {
checkSetupDone("consume");
consumeAsyncInternal(purchases, null, listener);
}
public static String getResponseDesc(int code) {
String[] iab_msgs = "0:OK/1:User Canceled/2:Unknown/3:Billing Unavailable/4:Item unavailable/5:Developer Error/6:Error/7:Item Already Owned/8:Item not owned".split("/");
String[] iabhelper_msgs = "0:OK/-1001:Remote exception during initialization/-1002:Bad response received/-1003:Purchase signature verification failed/-1004:Send intent failed/-1005:User cancelled/-1006:Unknown purchase response/-1007:Missing token/-1008:Unknown error/-1009:Subscriptions not available/-1010:Invalid consumption attempt".split("/");
if (code <= -1000) {
int index = (-1000) - code;
return (index < 0 || index >= iabhelper_msgs.length) ? String.valueOf(code) + ":Unknown IAB Helper Error" : iabhelper_msgs[index];
}
if (code < 0 || code >= iab_msgs.length) {
return String.valueOf(code) + ":Unknown";
}
return iab_msgs[code];
}
void checkSetupDone(String operation) {
if (!this.mSetupDone) {
logError("Illegal state for operation (" + operation + "): IAB helper is not set up.");
throw new IllegalStateException("IAB helper is not set up. Can't perform operation: " + operation);
}
}
int getResponseCodeFromBundle(Bundle b) {
Object o = b.get("RESPONSE_CODE");
if (o == null) {
logDebug("Bundle with null response code, assuming OK (known issue)");
return 0;
}
if (o instanceof Integer) {
return ((Integer) o).intValue();
}
if (o instanceof Long) {
return (int) ((Long) o).longValue();
}
logError("Unexpected type for bundle response code.");
logError(o.getClass().getName());
throw new RuntimeException("Unexpected type for bundle response code: " + o.getClass().getName());
}
int getResponseCodeFromIntent(Intent i) {
Object o = i.getExtras().get("RESPONSE_CODE");
if (o == null) {
logError("Intent with no response code, assuming OK (known issue)");
return 0;
}
if (o instanceof Integer) {
return ((Integer) o).intValue();
}
if (o instanceof Long) {
return (int) ((Long) o).longValue();
}
logError("Unexpected type for intent response code.");
logError(o.getClass().getName());
throw new RuntimeException("Unexpected type for intent response code: " + o.getClass().getName());
}
int queryPurchaseHistory(Inventory inv, String itemType, IInAppBillingService service) throws JSONException, RemoteException {
if (this.mDisposed) {
logDebug("queryPurchase History - Biller disposed. Returning...");
return 0;
}
logDebug("Querying owned items' purchase history, item type: " + itemType);
logDebug("Package name: " + this.mContext.getPackageName());
String continueToken = null;
do {
logDebug("Calling getPurchaseHistory with continuation token: " + continueToken);
Bundle ownedItems = service.getPurchaseHistory(6, this.mContext.getPackageName(), itemType, continueToken, new Bundle());
int response = getResponseCodeFromBundle(ownedItems);
logDebug("Purchase history response: " + String.valueOf(response));
if (response != 0) {
logDebug("getPurchaseHistory() failed: " + getResponseDesc(response));
return response;
}
if (!ownedItems.containsKey(RESPONSE_INAPP_ITEM_LIST) || !ownedItems.containsKey(RESPONSE_INAPP_PURCHASE_DATA_LIST) || !ownedItems.containsKey(RESPONSE_INAPP_SIGNATURE_LIST)) {
logError("Bundle returned from getPurchaseHistory() doesn't contain required fields.");
return IABHELPER_BAD_RESPONSE;
}
ArrayList<String> ownedSkus = ownedItems.getStringArrayList(RESPONSE_INAPP_ITEM_LIST);
for (int i = 0; i < ownedSkus.size(); i++) {
String sku = ownedSkus.get(i);
logDebug("This sku has purchase history: " + sku);
inv.addPurchaseToSubscriptionPurchaseHistory(sku);
}
continueToken = ownedItems.getString(INAPP_CONTINUATION_TOKEN);
logDebug("Continuation token: " + continueToken);
} while (!TextUtils.isEmpty(continueToken));
return 0 != 0 ? IABHELPER_VERIFICATION_FAILED : 0;
}
public int queryPurchases(Inventory inv, String itemType, IInAppBillingService service) throws JSONException, RemoteException {
if (this.mDisposed) {
logDebug("queryPurchases - Biller disposed. Returning...");
return 0;
}
logDebug("Querying owned items, item type: " + itemType);
logDebug("Package name: " + this.mContext.getPackageName());
String continueToken = null;
do {
logDebug("Calling getPurchases with continuation token: " + continueToken);
Bundle ownedItems = service.getPurchases(3, this.mContext.getPackageName(), itemType, continueToken);
int response = getResponseCodeFromBundle(ownedItems);
logDebug("Owned items response: " + String.valueOf(response));
if (response != 0) {
logDebug("getPurchases() failed: " + getResponseDesc(response));
return response;
}
if (!ownedItems.containsKey(RESPONSE_INAPP_ITEM_LIST) || !ownedItems.containsKey(RESPONSE_INAPP_PURCHASE_DATA_LIST) || !ownedItems.containsKey(RESPONSE_INAPP_SIGNATURE_LIST)) {
logError("Bundle returned from getPurchases() doesn't contain required fields.");
return IABHELPER_BAD_RESPONSE;
}
ArrayList<String> ownedSkus = ownedItems.getStringArrayList(RESPONSE_INAPP_ITEM_LIST);
ArrayList<String> purchaseDataList = ownedItems.getStringArrayList(RESPONSE_INAPP_PURCHASE_DATA_LIST);
ArrayList<String> signatureList = ownedItems.getStringArrayList(RESPONSE_INAPP_SIGNATURE_LIST);
for (int i = 0; i < purchaseDataList.size(); i++) {
String purchaseData = purchaseDataList.get(i);
String signature = signatureList.get(i);
String sku = ownedSkus.get(i);
logDebug("Sku is owned: " + sku);
Purchase purchase = new Purchase(itemType, purchaseData, signature);
if (TextUtils.isEmpty(purchase.getToken())) {
logWarn("BUG: empty/null token!");
logDebug("Purchase data: " + purchaseData);
}
inv.addPurchase(purchase);
}
continueToken = ownedItems.getString(INAPP_CONTINUATION_TOKEN);
logDebug("Continuation token: " + continueToken);
} while (!TextUtils.isEmpty(continueToken));
return 0 != 0 ? IABHELPER_VERIFICATION_FAILED : 0;
}
int querySkuDetails(String itemType, Inventory inv, List<String> moreSkus, IInAppBillingService iInAppBillingService) throws RemoteException, JSONException {
logDebug("Querying SKU details.");
ArrayList<String> skuList = new ArrayList<>();
skuList.addAll(inv.getAllOwnedSkus(itemType));
if (moreSkus != null) {
skuList.addAll(moreSkus);
}
if (skuList.size() == 0) {
logDebug("queryPrices: nothing to do because there are no SKUs.");
return 0;
}
while (skuList.size() > 0) {
int endIndex = Math.min(20, skuList.size());
ArrayList<String> chunk = new ArrayList<>();
for (int t = 0; t < endIndex; t++) {
chunk.add(skuList.get(t));
}
Bundle querySkus = new Bundle();
querySkus.putStringArrayList(GET_SKU_DETAILS_ITEM_LIST, chunk);
Bundle skuDetails = iInAppBillingService.getSkuDetails(3, this.mContext.getPackageName(), itemType, querySkus);
skuList.removeAll(chunk);
if (!skuDetails.containsKey(RESPONSE_GET_SKU_DETAILS_LIST)) {
int response = getResponseCodeFromBundle(skuDetails);
if (response != 0) {
logDebug("getSkuDetails() failed: " + getResponseDesc(response));
return response;
}
logError("getSkuDetails() returned a bundle with neither an error nor a detail list.");
return IABHELPER_BAD_RESPONSE;
}
ArrayList<String> responseList = skuDetails.getStringArrayList(RESPONSE_GET_SKU_DETAILS_LIST);
Iterator<String> it = responseList.iterator();
while (it.hasNext()) {
String thisResponse = it.next();
SkuDetails d = new SkuDetails(itemType, thisResponse);
inv.addSkuDetails(d);
}
}
return 0;
}
void consumeAsyncInternal(final List<Purchase> purchases, final OnConsumeFinishedListener singleListener, final OnConsumeMultiFinishedListener multiListener) {
this.serviceManager.workWith(new BillingServiceProcessor() {
@Override
public void workWith(IInAppBillingService service) {
List<IabResult> results = new ArrayList<>();
for (Purchase purchase : purchases) {
try {
IabHelper.this.consume(purchase, service);
results.add(new IabResult(0, "Successful consume of sku " + purchase.getSku()));
} catch (IabException ex) {
results.add(ex.getResult());
}
}
if (!IabHelper.this.mDisposed && singleListener != null) {
try {
singleListener.onConsumeFinished((Purchase) purchases.get(0), results.get(0));
} catch (JSONException e) {
e.printStackTrace();
}
}
if (!IabHelper.this.mDisposed && multiListener != null) {
multiListener.onConsumeMultiFinished(purchases, results);
}
}
});
}
public static String byteArrayToHexString(byte[] a) {
StringBuilder sb = new StringBuilder(a.length * 2);
for (byte b : a) {
sb.append(String.format("%02x", Integer.valueOf(b & 255)));
}
return sb.toString();
}
void logDebug(String msg) {
Log.i("UnityIAP", msg);
}
void logError(String msg) {
Log.e(this.mDebugTag, "In-app billing error: " + msg);
}
void logWarn(String msg) {
Log.w(this.mDebugTag, "In-app billing warning: " + msg);
}
}