improve android payments

GodotPaymentV3 currently consumes purchased item right after purchasing.
But, some in-app item should not consume like "remove ads permanently"
So, I added "setAutoConsume(boolean)", "requestPurchased()",
"consume(sku_string)".
AutoConsume is true by default as before.

usage:

func _ready():
	var payment = Globals.get_singleton("GodotPayments")
	payment.setPurchaseCallbackId(get_instance_ID())
	payment.setAutoConsume(false) # default : true
	payment.requestPurchased() # callback : has_purchased
	payment.purchase("item_name") # callback : purchase_success,
purchase_fail, purchase_cancel, purchase_owned
	payment.consume("item_name") # callback : consume_success

func purchase_success(receipt, signature, sku):
	print("purchase_success : ", sku)

func purchase_fail():
	print("purchase_fail")

func purchase_cancel():
	print("purchase_cancel")

func purchase_owned(sku):
	print("purchase_owned : ", sku)

func consume_success(receipt, signature, sku):
	print("consume_success : ", sku)

func has_purchased(receipt, signature, sku):
	if sku == "":
		print("has_purchased : nothing")
	else:
		print("has_purchased : ", sku)
This commit is contained in:
volzhs 2015-10-28 15:48:37 +09:00
parent bd736e5af2
commit 3fbaa479e3
3 changed files with 152 additions and 43 deletions

View File

@ -27,7 +27,7 @@ public class GodotPaymentV3 extends Godot.SingletonBase {
activity.getPaymentsManager().requestPurchase(sku, transactionId); activity.getPaymentsManager().requestPurchase(sku, transactionId);
} }
}); });
}; }
/* public string requestPurchasedTicket(){ /* public string requestPurchasedTicket(){
activity.getPaymentsManager() activity.getPaymentsManager()
@ -42,7 +42,7 @@ public class GodotPaymentV3 extends Godot.SingletonBase {
public GodotPaymentV3(Activity p_activity) { public GodotPaymentV3(Activity p_activity) {
registerClass("GodotPayments", new String[] {"purchase", "setPurchaseCallbackId", "setPurchaseValidationUrlPrefix", "setTransactionId", "getSignature", "consumeUnconsumedPurchases"}); registerClass("GodotPayments", new String[] {"purchase", "setPurchaseCallbackId", "setPurchaseValidationUrlPrefix", "setTransactionId", "getSignature", "consumeUnconsumedPurchases", "requestPurchased", "setAutoConsume", "consume"});
activity=(Godot) p_activity; activity=(Godot) p_activity;
} }
@ -54,7 +54,6 @@ public class GodotPaymentV3 extends Godot.SingletonBase {
activity.getPaymentsManager().consumeUnconsumedPurchases(); activity.getPaymentsManager().consumeUnconsumedPurchases();
} }
}); });
} }
private String signature; private String signature;
@ -63,25 +62,26 @@ public class GodotPaymentV3 extends Godot.SingletonBase {
} }
public void callbackSuccess(String ticket, String signature){ public void callbackSuccess(String ticket, String signature, String sku){
// Log.d(this.getClass().getName(), "PRE-Send callback to purchase success"); // Log.d(this.getClass().getName(), "PRE-Send callback to purchase success");
GodotLib.callobject(purchaseCallbackId, "purchase_success", new Object[]{ticket, signature}); GodotLib.callobject(purchaseCallbackId, "purchase_success", new Object[]{ticket, signature, sku});
// Log.d(this.getClass().getName(), "POST-Send callback to purchase success"); // Log.d(this.getClass().getName(), "POST-Send callback to purchase success");
} }
public void callbackSuccessProductMassConsumed(String ticket, String signature, String sku){ 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(), "PRE-Send callback to consume success");
GodotLib.calldeferred(purchaseCallbackId, "consume_success", new Object[]{ticket, signature, sku}); Log.d(this.getClass().getName(), "callbackSuccessProductMassConsumed > "+ticket+","+signature+","+sku);
// Log.d(this.getClass().getName(), "POST-Send callback to consume success"); 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 callbackSuccessNoUnconsumedPurchases(){
GodotLib.calldeferred(purchaseCallbackId, "no_validation_required", new Object[]{}); GodotLib.calldeferred(purchaseCallbackId, "no_validation_required", new Object[]{});
} }
public void callbackFail(){ public void callbackFail(){
GodotLib.calldeferred(purchaseCallbackId, "purchase_fail", new Object[]{}); GodotLib.calldeferred(purchaseCallbackId, "purchase_fail", new Object[]{});
// GodotLib.callobject(purchaseCallbackId, "purchase_fail", new Object[]{}); // GodotLib.callobject(purchaseCallbackId, "purchase_fail", new Object[]{});
} }
public void callbackCancel(){ public void callbackCancel(){
@ -89,6 +89,10 @@ public class GodotPaymentV3 extends Godot.SingletonBase {
// GodotLib.callobject(purchaseCallbackId, "purchase_cancel", new Object[]{}); // GodotLib.callobject(purchaseCallbackId, "purchase_cancel", new Object[]{});
} }
public void callbackAlreadyOwned(String sku){
GodotLib.calldeferred(purchaseCallbackId, "purchase_owned", new Object[]{sku});
}
public int getPurchaseCallbackId() { public int getPurchaseCallbackId() {
return purchaseCallbackId; return purchaseCallbackId;
} }
@ -97,8 +101,6 @@ public class GodotPaymentV3 extends Godot.SingletonBase {
this.purchaseCallbackId = purchaseCallbackId; this.purchaseCallbackId = purchaseCallbackId;
} }
public String getPurchaseValidationUrlPrefix(){ public String getPurchaseValidationUrlPrefix(){
return this.purchaseValidationUrlPrefix ; return this.purchaseValidationUrlPrefix ;
} }
@ -107,12 +109,10 @@ public class GodotPaymentV3 extends Godot.SingletonBase {
this.purchaseValidationUrlPrefix = url; this.purchaseValidationUrlPrefix = url;
} }
public String getAccessToken() { public String getAccessToken() {
return accessToken; return accessToken;
} }
public void setAccessToken(String accessToken) { public void setAccessToken(String accessToken) {
this.accessToken = accessToken; this.accessToken = accessToken;
} }
@ -125,4 +125,30 @@ public class GodotPaymentV3 extends Godot.SingletonBase {
return this.transactionId; return this.transactionId;
} }
// request purchased items are not consumed
public void requestPurchased(){
activity.getPaymentsManager().setBaseSingleton(this);
activity.runOnUiThread(new Runnable() {
@Override
public void run() {
activity.getPaymentsManager().requestPurchased();
}
});
}
// callback for requestPurchased()
public void callbackPurchased(String receipt, String signature, String sku){
GodotLib.calldeferred(purchaseCallbackId, "has_purchased", new Object[]{receipt, signature, sku});
}
// consume item automatically after purchase. default is true.
public void setAutoConsume(boolean autoConsume){
activity.getPaymentsManager().setAutoConsume(autoConsume);
}
// consume a specific item
public void consume(String sku){
activity.getPaymentsManager().consume(sku);
}
} }

View File

@ -25,10 +25,8 @@ import com.android.vending.billing.IInAppBillingService;
public class PaymentsManager { public class PaymentsManager {
public static final int BILLING_RESPONSE_RESULT_OK = 0; public static final int BILLING_RESPONSE_RESULT_OK = 0;
public static final int REQUEST_CODE_FOR_PURCHASE = 0x1001; public static final int REQUEST_CODE_FOR_PURCHASE = 0x1001;
private static boolean auto_consume = true;
private Activity activity; private Activity activity;
IInAppBillingService mService; IInAppBillingService mService;
@ -69,13 +67,12 @@ public class PaymentsManager {
} }
@Override @Override
public void onServiceConnected(ComponentName name, public void onServiceConnected(ComponentName name, IBinder service) {
IBinder service) { mService = IInAppBillingService.Stub.asInterface(service);
mService = IInAppBillingService.Stub.asInterface(service);
} }
}; };
public void requestPurchase(String sku, String transactionId){ public void requestPurchase(final String sku, String transactionId){
new PurchaseTask(mService, Godot.getInstance()) { new PurchaseTask(mService, Godot.getInstance()) {
@Override @Override
@ -88,6 +85,12 @@ public class PaymentsManager {
protected void canceled() { protected void canceled() {
godotPaymentV3.callbackCancel(); godotPaymentV3.callbackCancel();
} }
@Override
protected void alreadyOwned() {
godotPaymentV3.callbackAlreadyOwned(sku);
}
}.purchase(sku, transactionId); }.purchase(sku, transactionId);
} }
@ -114,26 +117,82 @@ public class PaymentsManager {
}.consumeItAll(); }.consumeItAll();
} }
public void requestPurchased(){
try{
PaymentsCache pc = new PaymentsCache(Godot.getInstance());
// Log.d("godot", "requestPurchased for " + activity.getPackageName());
Bundle bundle = mService.getPurchases(3, activity.getPackageName(), "inapp",null);
/*
for (String key : bundle.keySet()) {
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){
final ArrayList<String> myPurchases = bundle.getStringArrayList("INAPP_PURCHASE_DATA_LIST");
final ArrayList<String> mySignatures = bundle.getStringArrayList("INAPP_DATA_SIGNATURE_LIST");
if (myPurchases == null || myPurchases.size() == 0){
// Log.d("godot", "No purchases!");
godotPaymentV3.callbackPurchased("", "", "");
return;
}
// Log.d("godot", "# products are purchased:" + myPurchases.size());
for (int i=0;i<myPurchases.size();i++)
{
try{
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);
// Log.d("godot", "purchased item:" + token + "\n" + receipt);
pc.setConsumableValue("ticket_signautre", sku, signature);
pc.setConsumableValue("ticket", sku, receipt);
pc.setConsumableFlag("block", sku, true);
pc.setConsumableValue("token", sku, token);
godotPaymentV3.callbackPurchased(receipt, signature, sku);
} catch (JSONException e) {
}
}
}
}catch(Exception e){
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); godotPaymentV3.callbackSuccess(ticket, signature, sku);
new ConsumeTask(mService, activity) {
@Override if (auto_consume){
protected void success(String ticket) { new ConsumeTask(mService, activity) {
// godotPaymentV3.callbackSuccess("");
}
@Override @Override
protected void error(String message) { protected void success(String ticket) {
godotPaymentV3.callbackFail(); // godotPaymentV3.callbackSuccess("");
}
} @Override
}.consume(sku); protected void error(String message) {
godotPaymentV3.callbackFail();
}
}.consume(sku);
}
// godotPaymentV3.callbackSuccess(new PaymentsCache(activity).getConsumableValue("ticket", sku),signature); // godotPaymentV3.callbackSuccess(new PaymentsCache(activity).getConsumableValue("ticket", sku),signature);
// godotPaymentV3.callbackSuccess(ticket); // godotPaymentV3.callbackSuccess(ticket);
@ -151,7 +210,7 @@ public class PaymentsManager {
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){
@ -165,7 +224,7 @@ public class PaymentsManager {
@Override @Override
protected void success(String ticket) { protected void success(String ticket) {
godotPaymentV3.callbackSuccess(ticket, null); godotPaymentV3.callbackSuccess(ticket, null, sku);
} }
@ -192,11 +251,31 @@ public class PaymentsManager {
}.validatePurchase(sku); }.validatePurchase(sku);
} }
public void setAutoConsume(boolean autoConsume){
auto_consume = autoConsume;
}
public void consume(final String sku){
new ConsumeTask(mService, activity) {
@Override
protected void success(String ticket) {
godotPaymentV3.callbackSuccessProductMassConsumed(ticket, "", sku);
}
@Override
protected void error(String message) {
godotPaymentV3.callbackFail();
}
}.consume(sku);
}
private GodotPaymentV3 godotPaymentV3; private GodotPaymentV3 godotPaymentV3;
public void setBaseSingleton(GodotPaymentV3 godotPaymentV3) { public void setBaseSingleton(GodotPaymentV3 godotPaymentV3) {
this.godotPaymentV3 = godotPaymentV3; this.godotPaymentV3 = godotPaymentV3;
} }
} }

View File

@ -62,7 +62,11 @@ abstract public class PurchaseTask {
// Log.d("XXX", "Buy intent response code: " + responseCode); // Log.d("XXX", "Buy intent response code: " + responseCode);
if(responseCode == 1 || responseCode == 3 || responseCode == 4){ if(responseCode == 1 || responseCode == 3 || responseCode == 4){
canceled(); canceled();
return ; return;
}
if(responseCode == 7){
alreadyOwned();
return;
} }
@ -92,6 +96,6 @@ abstract public class PurchaseTask {
abstract protected void error(String message); abstract protected void error(String message);
abstract protected void canceled(); abstract protected void canceled();
abstract protected void alreadyOwned();
} }