Merge pull request #5415 from volzhs/improve-android-payment
Improve android payment
This commit is contained in:
commit
9213400cd5
@ -28,96 +28,91 @@
|
|||||||
/*************************************************************************/
|
/*************************************************************************/
|
||||||
package org.godotengine.godot;
|
package org.godotengine.godot;
|
||||||
|
|
||||||
import org.godotengine.godot.Dictionary;
|
|
||||||
import android.app.Activity;
|
import android.app.Activity;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
|
import org.godotengine.godot.payments.PaymentsManager;
|
||||||
|
import org.json.JSONException;
|
||||||
|
import org.json.JSONObject;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
|
||||||
public class GodotPaymentV3 extends Godot.SingletonBase {
|
public class GodotPaymentV3 extends Godot.SingletonBase {
|
||||||
|
|
||||||
private Godot activity;
|
private Godot activity;
|
||||||
|
|
||||||
private Integer purchaseCallbackId = 0;
|
private Integer purchaseCallbackId = 0;
|
||||||
|
|
||||||
private String accessToken;
|
private String accessToken;
|
||||||
|
|
||||||
private String purchaseValidationUrlPrefix;
|
private String purchaseValidationUrlPrefix;
|
||||||
|
|
||||||
private String transactionId;
|
private String transactionId;
|
||||||
|
private PaymentsManager mPaymentManager;
|
||||||
|
private Dictionary mSkuDetails = new Dictionary();
|
||||||
|
|
||||||
public void purchase( String _sku, String _transactionId) {
|
public void purchase(final String sku, final String transactionId) {
|
||||||
final String sku = _sku;
|
|
||||||
final String transactionId = _transactionId;
|
|
||||||
activity.getPaymentsManager().setBaseSingleton(this);
|
|
||||||
activity.runOnUiThread(new Runnable() {
|
activity.runOnUiThread(new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
activity.getPaymentsManager().requestPurchase(sku, transactionId);
|
mPaymentManager.requestPurchase(sku, transactionId);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/* public string requestPurchasedTicket(){
|
static public Godot.SingletonBase initialize(Activity p_activity) {
|
||||||
activity.getPaymentsManager()
|
|
||||||
|
return new GodotPaymentV3(p_activity);
|
||||||
}
|
}
|
||||||
|
|
||||||
*/
|
|
||||||
static public Godot.SingletonBase initialize(Activity p_activity) {
|
|
||||||
|
|
||||||
return new GodotPaymentV3(p_activity);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public GodotPaymentV3(Activity p_activity) {
|
public GodotPaymentV3(Activity p_activity) {
|
||||||
|
|
||||||
registerClass("GodotPayments", new String[] {"purchase", "setPurchaseCallbackId", "setPurchaseValidationUrlPrefix", "setTransactionId", "getSignature", "consumeUnconsumedPurchases", "requestPurchased", "setAutoConsume", "consume"});
|
registerClass("GodotPayments", new String[]{"purchase", "setPurchaseCallbackId", "setPurchaseValidationUrlPrefix", "setTransactionId", "getSignature", "consumeUnconsumedPurchases", "requestPurchased", "setAutoConsume", "consume", "querySkuDetails"});
|
||||||
activity=(Godot) p_activity;
|
activity = (Godot) p_activity;
|
||||||
|
mPaymentManager = activity.getPaymentsManager();
|
||||||
|
mPaymentManager.setBaseSingleton(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void consumeUnconsumedPurchases(){
|
public void consumeUnconsumedPurchases() {
|
||||||
activity.getPaymentsManager().setBaseSingleton(this);
|
|
||||||
activity.runOnUiThread(new Runnable() {
|
activity.runOnUiThread(new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
activity.getPaymentsManager().consumeUnconsumedPurchases();
|
mPaymentManager.consumeUnconsumedPurchases();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private String signature;
|
private String signature;
|
||||||
public String getSignature(){
|
|
||||||
return this.signature;
|
public String getSignature() {
|
||||||
|
return this.signature;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void callbackSuccess(String ticket, String signature, String sku) {
|
||||||
public void callbackSuccess(String ticket, String signature, String sku){
|
|
||||||
// Log.d(this.getClass().getName(), "PRE-Send callback to purchase success");
|
|
||||||
GodotLib.callobject(purchaseCallbackId, "purchase_success", new Object[]{ticket, signature, sku});
|
GodotLib.callobject(purchaseCallbackId, "purchase_success", new Object[]{ticket, signature, sku});
|
||||||
// Log.d(this.getClass().getName(), "POST-Send callback to purchase success");
|
|
||||||
}
|
|
||||||
|
|
||||||
public void callbackSuccessProductMassConsumed(String ticket, String signature, String sku){
|
|
||||||
// Log.d(this.getClass().getName(), "PRE-Send callback to consume success");
|
|
||||||
Log.d(this.getClass().getName(), "callbackSuccessProductMassConsumed > "+ticket+","+signature+","+sku);
|
|
||||||
GodotLib.calldeferred(purchaseCallbackId, "consume_success", new Object[]{ticket, signature, sku});
|
|
||||||
// Log.d(this.getClass().getName(), "POST-Send callback to consume success");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void callbackSuccessNoUnconsumedPurchases(){
|
public void callbackSuccessProductMassConsumed(String ticket, String signature, String sku) {
|
||||||
GodotLib.calldeferred(purchaseCallbackId, "no_validation_required", new Object[]{});
|
Log.d(this.getClass().getName(), "callbackSuccessProductMassConsumed > " + ticket + "," + signature + "," + sku);
|
||||||
|
GodotLib.calldeferred(purchaseCallbackId, "consume_success", new Object[]{ticket, signature, sku});
|
||||||
}
|
}
|
||||||
|
|
||||||
public void callbackFail(){
|
public void callbackSuccessNoUnconsumedPurchases() {
|
||||||
|
GodotLib.calldeferred(purchaseCallbackId, "consume_not_required", new Object[]{});
|
||||||
|
}
|
||||||
|
|
||||||
|
public void callbackFailConsume() {
|
||||||
|
GodotLib.calldeferred(purchaseCallbackId, "consume_fail", new Object[]{});
|
||||||
|
}
|
||||||
|
|
||||||
|
public void callbackFail() {
|
||||||
GodotLib.calldeferred(purchaseCallbackId, "purchase_fail", new Object[]{});
|
GodotLib.calldeferred(purchaseCallbackId, "purchase_fail", new Object[]{});
|
||||||
// GodotLib.callobject(purchaseCallbackId, "purchase_fail", new Object[]{});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void callbackCancel(){
|
public void callbackCancel() {
|
||||||
GodotLib.calldeferred(purchaseCallbackId, "purchase_cancel", new Object[]{});
|
GodotLib.calldeferred(purchaseCallbackId, "purchase_cancel", new Object[]{});
|
||||||
// GodotLib.callobject(purchaseCallbackId, "purchase_cancel", new Object[]{});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void callbackAlreadyOwned(String sku){
|
public void callbackAlreadyOwned(String sku) {
|
||||||
GodotLib.calldeferred(purchaseCallbackId, "purchase_owned", new Object[]{sku});
|
GodotLib.calldeferred(purchaseCallbackId, "purchase_owned", new Object[]{sku});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -129,11 +124,11 @@ public class GodotPaymentV3 extends Godot.SingletonBase {
|
|||||||
this.purchaseCallbackId = purchaseCallbackId;
|
this.purchaseCallbackId = purchaseCallbackId;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getPurchaseValidationUrlPrefix(){
|
public String getPurchaseValidationUrlPrefix() {
|
||||||
return this.purchaseValidationUrlPrefix ;
|
return this.purchaseValidationUrlPrefix;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setPurchaseValidationUrlPrefix(String url){
|
public void setPurchaseValidationUrlPrefix(String url) {
|
||||||
this.purchaseValidationUrlPrefix = url;
|
this.purchaseValidationUrlPrefix = url;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -145,38 +140,79 @@ public class GodotPaymentV3 extends Godot.SingletonBase {
|
|||||||
this.accessToken = accessToken;
|
this.accessToken = accessToken;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setTransactionId(String transactionId){
|
public void setTransactionId(String transactionId) {
|
||||||
this.transactionId = transactionId;
|
this.transactionId = transactionId;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getTransactionId(){
|
public String getTransactionId() {
|
||||||
return this.transactionId;
|
return this.transactionId;
|
||||||
}
|
}
|
||||||
|
|
||||||
// request purchased items are not consumed
|
// request purchased items are not consumed
|
||||||
public void requestPurchased(){
|
public void requestPurchased() {
|
||||||
activity.getPaymentsManager().setBaseSingleton(this);
|
|
||||||
activity.runOnUiThread(new Runnable() {
|
activity.runOnUiThread(new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
activity.getPaymentsManager().requestPurchased();
|
mPaymentManager.requestPurchased();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// callback for requestPurchased()
|
// callback for requestPurchased()
|
||||||
public void callbackPurchased(String receipt, String signature, String sku){
|
public void callbackPurchased(String receipt, String signature, String sku) {
|
||||||
GodotLib.calldeferred(purchaseCallbackId, "has_purchased", new Object[]{receipt, signature, sku});
|
GodotLib.calldeferred(purchaseCallbackId, "has_purchased", new Object[]{receipt, signature, sku});
|
||||||
}
|
}
|
||||||
|
|
||||||
// consume item automatically after purchase. default is true.
|
// consume item automatically after purchase. default is true.
|
||||||
public void setAutoConsume(boolean autoConsume){
|
public void setAutoConsume(boolean autoConsume) {
|
||||||
activity.getPaymentsManager().setAutoConsume(autoConsume);
|
mPaymentManager.setAutoConsume(autoConsume);
|
||||||
}
|
}
|
||||||
|
|
||||||
// consume a specific item
|
// consume a specific item
|
||||||
public void consume(String sku){
|
public void consume(String sku) {
|
||||||
activity.getPaymentsManager().consume(sku);
|
mPaymentManager.consume(sku);
|
||||||
|
}
|
||||||
|
|
||||||
|
// query in app item detail info
|
||||||
|
public void querySkuDetails(String[] list) {
|
||||||
|
List<String> nKeys = Arrays.asList(list);
|
||||||
|
List<String> cKeys = Arrays.asList(mSkuDetails.get_keys());
|
||||||
|
ArrayList<String> fKeys = new ArrayList<String>();
|
||||||
|
for (String key : nKeys) {
|
||||||
|
if (!cKeys.contains(key)) {
|
||||||
|
fKeys.add(key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (fKeys.size() > 0) {
|
||||||
|
mPaymentManager.querySkuDetails(fKeys.toArray(new String[0]));
|
||||||
|
} else {
|
||||||
|
completeSkuDetail();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addSkuDetail(String itemJson) {
|
||||||
|
JSONObject o = null;
|
||||||
|
try {
|
||||||
|
o = new JSONObject(itemJson);
|
||||||
|
Dictionary item = new Dictionary();
|
||||||
|
item.put("type", o.optString("type"));
|
||||||
|
item.put("product_id", o.optString("productId"));
|
||||||
|
item.put("title", o.optString("title"));
|
||||||
|
item.put("description", o.optString("description"));
|
||||||
|
item.put("price", o.optString("price"));
|
||||||
|
item.put("price_currency_code", o.optString("price_currency_code"));
|
||||||
|
item.put("price_amount", 0.000001d * o.optLong("price_amount_micros"));
|
||||||
|
mSkuDetails.put(item.get("product_id").toString(), item);
|
||||||
|
} catch (JSONException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void completeSkuDetail() {
|
||||||
|
GodotLib.calldeferred(purchaseCallbackId, "sku_details_complete", new Object[]{mSkuDetails});
|
||||||
|
}
|
||||||
|
|
||||||
|
public void errorSkuDetail(String errorMessage) {
|
||||||
|
GodotLib.calldeferred(purchaseCallbackId, "sku_details_error", new Object[]{errorMessage});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -28,27 +28,26 @@
|
|||||||
/*************************************************************************/
|
/*************************************************************************/
|
||||||
package org.godotengine.godot.payments;
|
package org.godotengine.godot.payments;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import android.os.RemoteException;
|
|
||||||
import android.app.Activity;
|
import android.app.Activity;
|
||||||
import android.content.ComponentName;
|
import android.content.ComponentName;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.content.ServiceConnection;
|
import android.content.ServiceConnection;
|
||||||
import android.os.IBinder;
|
|
||||||
import android.util.Log;
|
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
|
import android.os.IBinder;
|
||||||
|
import android.os.RemoteException;
|
||||||
|
import android.text.TextUtils;
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
import org.json.JSONException;
|
import com.android.vending.billing.IInAppBillingService;
|
||||||
import org.json.JSONObject;
|
|
||||||
import org.json.JSONStringer;
|
|
||||||
|
|
||||||
import org.godotengine.godot.Dictionary;
|
|
||||||
import org.godotengine.godot.Godot;
|
import org.godotengine.godot.Godot;
|
||||||
import org.godotengine.godot.GodotPaymentV3;
|
import org.godotengine.godot.GodotPaymentV3;
|
||||||
import com.android.vending.billing.IInAppBillingService;
|
import org.json.JSONException;
|
||||||
|
import org.json.JSONObject;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
public class PaymentsManager {
|
public class PaymentsManager {
|
||||||
|
|
||||||
@ -59,20 +58,20 @@ public class PaymentsManager {
|
|||||||
private Activity activity;
|
private Activity activity;
|
||||||
IInAppBillingService mService;
|
IInAppBillingService mService;
|
||||||
|
|
||||||
public void setActivity(Activity activity){
|
public void setActivity(Activity activity) {
|
||||||
this.activity = activity;
|
this.activity = activity;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static PaymentsManager createManager(Activity activity){
|
public static PaymentsManager createManager(Activity activity) {
|
||||||
PaymentsManager manager = new PaymentsManager(activity);
|
PaymentsManager manager = new PaymentsManager(activity);
|
||||||
return manager;
|
return manager;
|
||||||
}
|
}
|
||||||
|
|
||||||
private PaymentsManager(Activity activity){
|
private PaymentsManager(Activity activity) {
|
||||||
this.activity = activity;
|
this.activity = activity;
|
||||||
}
|
}
|
||||||
|
|
||||||
public PaymentsManager initService(){
|
public PaymentsManager initService() {
|
||||||
Intent intent = new Intent("com.android.vending.billing.InAppBillingService.BIND");
|
Intent intent = new Intent("com.android.vending.billing.InAppBillingService.BIND");
|
||||||
intent.setPackage("com.android.vending");
|
intent.setPackage("com.android.vending");
|
||||||
activity.bindService(
|
activity.bindService(
|
||||||
@ -82,25 +81,25 @@ public class PaymentsManager {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void destroy(){
|
public void destroy() {
|
||||||
if (mService != null) {
|
if (mService != null) {
|
||||||
activity.unbindService(mServiceConn);
|
activity.unbindService(mServiceConn);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ServiceConnection mServiceConn = new ServiceConnection() {
|
ServiceConnection mServiceConn = new ServiceConnection() {
|
||||||
@Override
|
@Override
|
||||||
public void onServiceDisconnected(ComponentName name) {
|
public void onServiceDisconnected(ComponentName name) {
|
||||||
mService = null;
|
mService = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onServiceConnected(ComponentName name, IBinder service) {
|
public void onServiceConnected(ComponentName name, IBinder service) {
|
||||||
mService = IInAppBillingService.Stub.asInterface(service);
|
mService = IInAppBillingService.Stub.asInterface(service);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
public void requestPurchase(final String sku, String transactionId){
|
public void requestPurchase(final String sku, String transactionId) {
|
||||||
new PurchaseTask(mService, Godot.getInstance()) {
|
new PurchaseTask(mService, Godot.getInstance()) {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -123,7 +122,7 @@ public class PaymentsManager {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void consumeUnconsumedPurchases(){
|
public void consumeUnconsumedPurchases() {
|
||||||
new ReleaseAllConsumablesTask(mService, activity) {
|
new ReleaseAllConsumablesTask(mService, activity) {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -133,85 +132,78 @@ public class PaymentsManager {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void error(String message) {
|
protected void error(String message) {
|
||||||
godotPaymentV3.callbackFail();
|
Log.d("godot", "consumeUnconsumedPurchases :" + message);
|
||||||
|
godotPaymentV3.callbackFailConsume();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void notRequired() {
|
protected void notRequired() {
|
||||||
|
Log.d("godot", "callbackSuccessNoUnconsumedPurchases :");
|
||||||
godotPaymentV3.callbackSuccessNoUnconsumedPurchases();
|
godotPaymentV3.callbackSuccessNoUnconsumedPurchases();
|
||||||
|
|
||||||
}
|
}
|
||||||
}.consumeItAll();
|
}.consumeItAll();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void requestPurchased(){
|
public void requestPurchased() {
|
||||||
try{
|
try {
|
||||||
PaymentsCache pc = new PaymentsCache(Godot.getInstance());
|
PaymentsCache pc = new PaymentsCache(Godot.getInstance());
|
||||||
|
|
||||||
// Log.d("godot", "requestPurchased for " + activity.getPackageName());
|
String continueToken = null;
|
||||||
Bundle bundle = mService.getPurchases(3, activity.getPackageName(), "inapp",null);
|
|
||||||
|
|
||||||
/*
|
do {
|
||||||
for (String key : bundle.keySet()) {
|
Bundle bundle = mService.getPurchases(3, activity.getPackageName(), "inapp", continueToken);
|
||||||
Object value = bundle.get(key);
|
|
||||||
Log.d("godot", String.format("%s %s (%s)", key, value.toString(), value.getClass().getName()));
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
if (bundle.getInt("RESPONSE_CODE") == 0){
|
if (bundle.getInt("RESPONSE_CODE") == 0) {
|
||||||
|
|
||||||
final ArrayList<String> myPurchases = bundle.getStringArrayList("INAPP_PURCHASE_DATA_LIST");
|
final ArrayList<String> myPurchases = bundle.getStringArrayList("INAPP_PURCHASE_DATA_LIST");
|
||||||
final ArrayList<String> mySignatures = bundle.getStringArrayList("INAPP_DATA_SIGNATURE_LIST");
|
final ArrayList<String> mySignatures = bundle.getStringArrayList("INAPP_DATA_SIGNATURE_LIST");
|
||||||
|
|
||||||
|
if (myPurchases == null || myPurchases.size() == 0) {
|
||||||
|
godotPaymentV3.callbackPurchased("", "", "");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (myPurchases == null || myPurchases.size() == 0){
|
for (int i = 0; i < myPurchases.size(); i++) {
|
||||||
// Log.d("godot", "No purchases!");
|
|
||||||
godotPaymentV3.callbackPurchased("", "", "");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Log.d("godot", "# products are purchased:" + myPurchases.size());
|
try {
|
||||||
for (int i=0;i<myPurchases.size();i++)
|
String receipt = myPurchases.get(i);
|
||||||
{
|
JSONObject inappPurchaseData = new JSONObject(receipt);
|
||||||
|
String sku = inappPurchaseData.getString("productId");
|
||||||
|
String token = inappPurchaseData.getString("purchaseToken");
|
||||||
|
String signature = mySignatures.get(i);
|
||||||
|
|
||||||
try{
|
pc.setConsumableValue("ticket_signautre", sku, signature);
|
||||||
String receipt = myPurchases.get(i);
|
pc.setConsumableValue("ticket", sku, receipt);
|
||||||
JSONObject inappPurchaseData = new JSONObject(receipt);
|
pc.setConsumableFlag("block", sku, true);
|
||||||
String sku = inappPurchaseData.getString("productId");
|
pc.setConsumableValue("token", sku, token);
|
||||||
String token = inappPurchaseData.getString("purchaseToken");
|
|
||||||
String signature = mySignatures.get(i);
|
|
||||||
// Log.d("godot", "purchased item:" + token + "\n" + receipt);
|
|
||||||
|
|
||||||
pc.setConsumableValue("ticket_signautre", sku, signature);
|
godotPaymentV3.callbackPurchased(receipt, signature, sku);
|
||||||
pc.setConsumableValue("ticket", sku, receipt);
|
} catch (JSONException e) {
|
||||||
pc.setConsumableFlag("block", sku, true);
|
}
|
||||||
pc.setConsumableValue("token", sku, token);
|
|
||||||
|
|
||||||
godotPaymentV3.callbackPurchased(receipt, signature, sku);
|
|
||||||
} catch (JSONException e) {
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
continueToken = bundle.getString("INAPP_CONTINUATION_TOKEN");
|
||||||
}
|
Log.d("godot", "continue token = " + continueToken);
|
||||||
}catch(Exception e){
|
} while (!TextUtils.isEmpty(continueToken));
|
||||||
|
} catch (Exception e) {
|
||||||
Log.d("godot", "Error requesting purchased products:" + e.getClass().getName() + ":" + e.getMessage());
|
Log.d("godot", "Error requesting purchased products:" + e.getClass().getName() + ":" + e.getMessage());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void processPurchaseResponse(int resultCode, Intent data) {
|
public void processPurchaseResponse(int resultCode, Intent data) {
|
||||||
new HandlePurchaseTask(activity){
|
new HandlePurchaseTask(activity) {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void success(final String sku, final String signature, final String ticket) {
|
protected void success(final String sku, final String signature, final String ticket) {
|
||||||
godotPaymentV3.callbackSuccess(ticket, signature, sku);
|
godotPaymentV3.callbackSuccess(ticket, signature, sku);
|
||||||
|
|
||||||
if (auto_consume){
|
if (auto_consume) {
|
||||||
new ConsumeTask(mService, activity) {
|
new ConsumeTask(mService, activity) {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void success(String ticket) {
|
protected void success(String ticket) {
|
||||||
// godotPaymentV3.callbackSuccess("");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -221,29 +213,23 @@ public class PaymentsManager {
|
|||||||
}
|
}
|
||||||
}.consume(sku);
|
}.consume(sku);
|
||||||
}
|
}
|
||||||
|
|
||||||
// godotPaymentV3.callbackSuccess(new PaymentsCache(activity).getConsumableValue("ticket", sku),signature);
|
|
||||||
// godotPaymentV3.callbackSuccess(ticket);
|
|
||||||
//validatePurchase(purchaseToken, sku);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void error(String message) {
|
protected void error(String message) {
|
||||||
godotPaymentV3.callbackFail();
|
godotPaymentV3.callbackFail();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void canceled() {
|
protected void canceled() {
|
||||||
godotPaymentV3.callbackCancel();
|
godotPaymentV3.callbackCancel();
|
||||||
|
|
||||||
}
|
}
|
||||||
}.handlePurchaseRequest(resultCode, data);
|
}.handlePurchaseRequest(resultCode, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void validatePurchase(String purchaseToken, final String sku){
|
public void validatePurchase(String purchaseToken, final String sku) {
|
||||||
|
|
||||||
new ValidateTask(activity, godotPaymentV3){
|
new ValidateTask(activity, godotPaymentV3) {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void success() {
|
protected void success() {
|
||||||
@ -253,13 +239,11 @@ public class PaymentsManager {
|
|||||||
@Override
|
@Override
|
||||||
protected void success(String ticket) {
|
protected void success(String ticket) {
|
||||||
godotPaymentV3.callbackSuccess(ticket, null, sku);
|
godotPaymentV3.callbackSuccess(ticket, null, sku);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void error(String message) {
|
protected void error(String message) {
|
||||||
godotPaymentV3.callbackFail();
|
godotPaymentV3.callbackFail();
|
||||||
|
|
||||||
}
|
}
|
||||||
}.consume(sku);
|
}.consume(sku);
|
||||||
|
|
||||||
@ -268,38 +252,142 @@ public class PaymentsManager {
|
|||||||
@Override
|
@Override
|
||||||
protected void error(String message) {
|
protected void error(String message) {
|
||||||
godotPaymentV3.callbackFail();
|
godotPaymentV3.callbackFail();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void canceled() {
|
protected void canceled() {
|
||||||
godotPaymentV3.callbackCancel();
|
godotPaymentV3.callbackCancel();
|
||||||
|
|
||||||
}
|
}
|
||||||
}.validatePurchase(sku);
|
}.validatePurchase(sku);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setAutoConsume(boolean autoConsume){
|
public void setAutoConsume(boolean autoConsume) {
|
||||||
auto_consume = autoConsume;
|
auto_consume = autoConsume;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void consume(final String sku){
|
public void consume(final String sku) {
|
||||||
new ConsumeTask(mService, activity) {
|
new ConsumeTask(mService, activity) {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void success(String ticket) {
|
protected void success(String ticket) {
|
||||||
godotPaymentV3.callbackSuccessProductMassConsumed(ticket, "", sku);
|
godotPaymentV3.callbackSuccessProductMassConsumed(ticket, "", sku);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void error(String message) {
|
protected void error(String message) {
|
||||||
godotPaymentV3.callbackFail();
|
godotPaymentV3.callbackFailConsume();
|
||||||
|
|
||||||
}
|
}
|
||||||
}.consume(sku);
|
}.consume(sku);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Workaround to bug where sometimes response codes come as Long instead of Integer
|
||||||
|
int getResponseCodeFromBundle(Bundle b) {
|
||||||
|
Object o = b.get("RESPONSE_CODE");
|
||||||
|
if (o == null) {
|
||||||
|
//logDebug("Bundle with null response code, assuming OK (known issue)");
|
||||||
|
return BILLING_RESPONSE_RESULT_OK;
|
||||||
|
} else if (o instanceof Integer) return ((Integer) o).intValue();
|
||||||
|
else if (o instanceof Long) return (int) ((Long) o).longValue();
|
||||||
|
else {
|
||||||
|
//logError("Unexpected type for bundle response code.");
|
||||||
|
//logError(o.getClass().getName());
|
||||||
|
throw new RuntimeException("Unexpected type for bundle response code: " + o.getClass().getName());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a human-readable description for the given response code.
|
||||||
|
*
|
||||||
|
* @param code The response code
|
||||||
|
* @return A human-readable string explaining the result code.
|
||||||
|
* It also includes the result code numerically.
|
||||||
|
*/
|
||||||
|
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;
|
||||||
|
if (index >= 0 && index < iabhelper_msgs.length) return iabhelper_msgs[index];
|
||||||
|
else return String.valueOf(code) + ":Unknown IAB Helper Error";
|
||||||
|
} else if (code < 0 || code >= iab_msgs.length)
|
||||||
|
return String.valueOf(code) + ":Unknown";
|
||||||
|
else
|
||||||
|
return iab_msgs[code];
|
||||||
|
}
|
||||||
|
|
||||||
|
public void querySkuDetails(final String[] list) {
|
||||||
|
(new Thread(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
ArrayList<String> skuList = new ArrayList<String>(Arrays.asList(list));
|
||||||
|
if (skuList.size() == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// Split the sku list in blocks of no more than 20 elements.
|
||||||
|
ArrayList<ArrayList<String>> packs = new ArrayList<ArrayList<String>>();
|
||||||
|
ArrayList<String> tempList;
|
||||||
|
int n = skuList.size() / 20;
|
||||||
|
int mod = skuList.size() % 20;
|
||||||
|
for (int i = 0; i < n; i++) {
|
||||||
|
tempList = new ArrayList<String>();
|
||||||
|
for (String s : skuList.subList(i * 20, i * 20 + 20)) {
|
||||||
|
tempList.add(s);
|
||||||
|
}
|
||||||
|
packs.add(tempList);
|
||||||
|
}
|
||||||
|
if (mod != 0) {
|
||||||
|
tempList = new ArrayList<String>();
|
||||||
|
for (String s : skuList.subList(n * 20, n * 20 + mod)) {
|
||||||
|
tempList.add(s);
|
||||||
|
}
|
||||||
|
packs.add(tempList);
|
||||||
|
|
||||||
|
for (ArrayList<String> skuPartList : packs) {
|
||||||
|
Bundle querySkus = new Bundle();
|
||||||
|
querySkus.putStringArrayList("ITEM_ID_LIST", skuPartList);
|
||||||
|
Bundle skuDetails = null;
|
||||||
|
try {
|
||||||
|
skuDetails = mService.getSkuDetails(3, activity.getPackageName(), "inapp", querySkus);
|
||||||
|
if (!skuDetails.containsKey("DETAILS_LIST")) {
|
||||||
|
int response = getResponseCodeFromBundle(skuDetails);
|
||||||
|
if (response != BILLING_RESPONSE_RESULT_OK) {
|
||||||
|
godotPaymentV3.errorSkuDetail(getResponseDesc(response));
|
||||||
|
} else {
|
||||||
|
godotPaymentV3.errorSkuDetail("No error but no detail list.");
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ArrayList<String> responseList = skuDetails.getStringArrayList("DETAILS_LIST");
|
||||||
|
|
||||||
|
for (String thisResponse : responseList) {
|
||||||
|
Log.d("godot", "response = "+thisResponse);
|
||||||
|
godotPaymentV3.addSkuDetail(thisResponse);
|
||||||
|
}
|
||||||
|
} catch (RemoteException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
godotPaymentV3.errorSkuDetail("RemoteException error!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
godotPaymentV3.completeSkuDetail();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})).start();
|
||||||
|
}
|
||||||
|
|
||||||
private GodotPaymentV3 godotPaymentV3;
|
private GodotPaymentV3 godotPaymentV3;
|
||||||
|
|
||||||
public void setBaseSingleton(GodotPaymentV3 godotPaymentV3) {
|
public void setBaseSingleton(GodotPaymentV3 godotPaymentV3) {
|
||||||
@ -307,4 +395,3 @@ public class PaymentsManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user