Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Merge branch 'payments_v3'

  • Loading branch information...
commit 64b75f4ca0fd91b4bef6667538df4c08a5d3a12b 2 parents 2b9bab8 + 8212560
@JohnCopic JohnCopic authored
View
2  ant/host-source/source/project/external/google-billingv3/manifest_permissions.xml
@@ -0,0 +1,2 @@
+<!-- Google Billing (Android Market) IAP -->
+<uses-permission android:name="com.android.vending.BILLING" />
View
144 ...oject/external/google-billingv3/src/com/android/vending/billing/IInAppBillingService.aidl
@@ -0,0 +1,144 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.vending.billing;
+
+import android.os.Bundle;
+
+/**
+ * InAppBillingService is the service that provides in-app billing version 3 and beyond.
+ * This service provides the following features:
+ * 1. Provides a new API to get details of in-app items published for the app including
+ * price, type, title and description.
+ * 2. The purchase flow is synchronous and purchase information is available immediately
+ * after it completes.
+ * 3. Purchase information of in-app purchases is maintained within the Google Play system
+ * till the purchase is consumed.
+ * 4. An API to consume a purchase of an inapp item. All purchases of one-time
+ * in-app items are consumable and thereafter can be purchased again.
+ * 5. An API to get current purchases of the user immediately. This will not contain any
+ * consumed purchases.
+ *
+ * All calls will give a response code with the following possible values
+ * RESULT_OK = 0 - success
+ * RESULT_USER_CANCELED = 1 - user pressed back or canceled a dialog
+ * RESULT_BILLING_UNAVAILABLE = 3 - this billing API version is not supported for the type requested
+ * RESULT_ITEM_UNAVAILABLE = 4 - requested SKU is not available for purchase
+ * RESULT_DEVELOPER_ERROR = 5 - invalid arguments provided to the API
+ * RESULT_ERROR = 6 - Fatal error during the API action
+ * RESULT_ITEM_ALREADY_OWNED = 7 - Failure to purchase since item is already owned
+ * RESULT_ITEM_NOT_OWNED = 8 - Failure to consume since item is not owned
+ */
+interface IInAppBillingService {
+ /**
+ * Checks support for the requested billing API version, package and in-app type.
+ * Minimum API version supported by this interface is 3.
+ * @param apiVersion the billing version which the app is using
+ * @param packageName the package name of the calling app
+ * @param type type of the in-app item being purchased "inapp" for one-time purchases
+ * and "subs" for subscription.
+ * @return RESULT_OK(0) on success, corresponding result code on failures
+ */
+ int isBillingSupported(int apiVersion, String packageName, String type);
+
+ /**
+ * Provides details of a list of SKUs
+ * Given a list of SKUs of a valid type in the skusBundle, this returns a bundle
+ * with a list JSON strings containing the productId, price, title and description.
+ * This API can be called with a maximum of 20 SKUs.
+ * @param apiVersion billing API version that the Third-party is using
+ * @param packageName the package name of the calling app
+ * @param skusBundle bundle containing a StringArrayList of SKUs with key "ITEM_ID_LIST"
+ * @return Bundle containing the following key-value pairs
+ * "RESPONSE_CODE" with int value, RESULT_OK(0) if success, other response codes on
+ * failure as listed above.
+ * "DETAILS_LIST" with a StringArrayList containing purchase information
+ * in JSON format similar to:
+ * '{ "productId" : "exampleSku", "type" : "inapp", "price" : "$5.00",
+ * "title : "Example Title", "description" : "This is an example description" }'
+ */
+ Bundle getSkuDetails(int apiVersion, String packageName, String type, in Bundle skusBundle);
+
+ /**
+ * Returns a pending intent to launch the purchase flow for an in-app item by providing a SKU,
+ * the type, a unique purchase token and an optional developer payload.
+ * @param apiVersion billing API version that the app is using
+ * @param packageName package name of the calling app
+ * @param sku the SKU of the in-app item as published in the developer console
+ * @param type the type of the in-app item ("inapp" for one-time purchases
+ * and "subs" for subscription).
+ * @param developerPayload optional argument to be sent back with the purchase information
+ * @return Bundle containing the following key-value pairs
+ * "RESPONSE_CODE" with int value, RESULT_OK(0) if success, other response codes on
+ * failure as listed above.
+ * "BUY_INTENT" - PendingIntent to start the purchase flow
+ *
+ * The Pending intent should be launched with startIntentSenderForResult. When purchase flow
+ * has completed, the onActivityResult() will give a resultCode of OK or CANCELED.
+ * If the purchase is successful, the result data will contain the following key-value pairs
+ * "RESPONSE_CODE" with int value, RESULT_OK(0) if success, other response codes on
+ * failure as listed above.
+ * "INAPP_PURCHASE_DATA" - String in JSON format similar to
+ * '{"orderId":"12999763169054705758.1371079406387615",
+ * "packageName":"com.example.app",
+ * "productId":"exampleSku",
+ * "purchaseTime":1345678900000,
+ * "purchaseToken" : "122333444455555",
+ * "developerPayload":"example developer payload" }'
+ * "INAPP_DATA_SIGNATURE" - String containing the signature of the purchase data that
+ * was signed with the private key of the developer
+ * TODO: change this to app-specific keys.
+ */
+ Bundle getBuyIntent(int apiVersion, String packageName, String sku, String type,
+ String developerPayload);
+
+ /**
+ * Returns the current SKUs owned by the user of the type and package name specified along with
+ * purchase information and a signature of the data to be validated.
+ * This will return all SKUs that have been purchased in V3 and managed items purchased using
+ * V1 and V2 that have not been consumed.
+ * @param apiVersion billing API version that the app is using
+ * @param packageName package name of the calling app
+ * @param type the type of the in-app items being requested
+ * ("inapp" for one-time purchases and "subs" for subscription).
+ * @param continuationToken to be set as null for the first call, if the number of owned
+ * skus are too many, a continuationToken is returned in the response bundle.
+ * This method can be called again with the continuation token to get the next set of
+ * owned skus.
+ * @return Bundle containing the following key-value pairs
+ * "RESPONSE_CODE" with int value, RESULT_OK(0) if success, other response codes on
+ * failure as listed above.
+ * "INAPP_PURCHASE_ITEM_LIST" - StringArrayList containing the list of SKUs
+ * "INAPP_PURCHASE_DATA_LIST" - StringArrayList containing the purchase information
+ * "INAPP_DATA_SIGNATURE_LIST"- StringArrayList containing the signatures
+ * of the purchase information
+ * "INAPP_CONTINUATION_TOKEN" - String containing a continuation token for the
+ * next set of in-app purchases. Only set if the
+ * user has more owned skus than the current list.
+ */
+ Bundle getPurchases(int apiVersion, String packageName, String type, String continuationToken);
+
+ /**
+ * Consume the last purchase of the given SKU. This will result in this item being removed
+ * from all subsequent responses to getPurchases() and allow re-purchase of this item.
+ * @param apiVersion billing API version that the app is using
+ * @param packageName package name of the calling app
+ * @param purchaseToken token in the purchase information JSON that identifies the purchase
+ * to be consumed
+ * @return 0 if consumption succeeded. Appropriate error values for failures.
+ */
+ int consumePurchase(int apiVersion, String packageName, String purchaseToken);
+}
View
2  ant/host-source/source/project/src/moai/MoaiKeyboard.java
@@ -22,7 +22,7 @@
import android.widget.TextView;
// These are necessary for the mKeyInTextView hack
-import android.widget.EditText;Ï
+import android.widget.EditText;
import android.text.TextWatcher;
import android.text.Editable;
View
290 ant/host-source/source/project/src/moai/google-billingv3/MoaiGoogleBilling.java
@@ -0,0 +1,290 @@
+//----------------------------------------------------------------//
+// Copyright (c) 2010-2011 Zipline Games, Inc.
+// All Rights Reserved.
+// http://getmoai.com
+//----------------------------------------------------------------//
+
+package com.ziplinegames.moai;
+
+import android.app.Activity;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+
+import com.android.vending.billing.IInAppBillingService;
+import android.app.PendingIntent;
+import android.content.ServiceConnection;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.os.Bundle;
+import android.os.IBinder;
+import android.os.RemoteException;
+
+import org.json.JSONArray;
+import org.json.JSONObject;
+import org.json.JSONException;
+
+//================================================================//
+// MoaiGoogleBilling
+//================================================================//
+public class MoaiGoogleBilling {
+
+ private static Activity sActivity = null;
+ private static IInAppBillingService sService = null;
+ private static ServiceConnection sServiceConn = null;
+
+ private static boolean sInAppSupported = false;
+ private static boolean sSubscriptionSupported = false;
+
+ // purchase types
+ public static final String PURCHASE_TYPE_INAPP = "inapp";
+ public static final String PURCHASE_TYPE_SUBSCRIPTION = "subs";
+
+ // Billing response codes
+ public static final int BILLING_RESPONSE_RESULT_OK = 0;
+ public static final int BILLING_RESPONSE_RESULT_USER_CANCELED = 1;
+ public static final int BILLING_RESPONSE_RESULT_BILLING_UNAVAILABLE = 3;
+ public static final int BILLING_RESPONSE_RESULT_ITEM_UNAVAILABLE = 4;
+ 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;
+
+ // AKU callbacks
+ protected static native void AKUNotifyGooglePurchaseResponseReceived ( int responseCode, String jsonInfo );
+
+ //----------------------------------------------------------------//
+ public static void onCreate ( Activity activity ) {
+
+ MoaiLog.i ( "MoaiGoogleBilling onCreate: Initializing Google Billing" );
+
+ sActivity = activity;
+
+ sServiceConn = new ServiceConnection () {
+
+ //--------------------------------------------------------//
+ @Override
+ public void onServiceDisconnected ( ComponentName name ) {
+
+ sService = null;
+ }
+
+ //--------------------------------------------------------//
+ @Override
+ public void onServiceConnected ( ComponentName name, IBinder service ) {
+
+ sService = IInAppBillingService.Stub.asInterface ( service );
+
+ // check supported billing types
+ try {
+
+ String packageName = sActivity.getPackageName ();
+
+ // in app purchases
+ int response = sService.isBillingSupported ( 3, packageName, PURCHASE_TYPE_INAPP );
+ if ( response == BILLING_RESPONSE_RESULT_OK ) {
+ sInAppSupported = true;
+ MoaiLog.i ( "MoaiGoogleBilling : In-app supported" );
+ } else {
+ sInAppSupported = false;
+ MoaiLog.i ( "MoaiGoogleBilling : In-app not supported" );
+ }
+
+ // subscriptions
+ response = sService.isBillingSupported (3, packageName, PURCHASE_TYPE_SUBSCRIPTION );
+ if ( response == BILLING_RESPONSE_RESULT_OK) {
+ sSubscriptionSupported = true;
+ MoaiLog.i ( "MoaiGoogleBilling : Subscriptions supported" );
+ }
+ else {
+ sSubscriptionSupported = false;
+ MoaiLog.i ( "MoaiGoogleBilling : Subscriptions not supported" );
+ }
+
+ } catch ( RemoteException e ) {
+
+ e.printStackTrace ();
+ }
+ }
+ };
+
+ sActivity.bindService ( new Intent ( "com.android.vending.billing.InAppBillingService.BIND" ), sServiceConn, Context.BIND_AUTO_CREATE );
+ }
+
+ //----------------------------------------------------------------//
+ public static void onDestroy () {
+
+ MoaiLog.i ( "MoaiGoogleBilling onDestroy: Unbinding billing service" );
+
+ if ( sServiceConn != null ) {
+
+ sActivity.unbindService ( sServiceConn );
+ }
+ }
+
+ //----------------------------------------------------------------//
+ public static void onActivityResult ( int requestCode, int resultCode, Intent data ) {
+
+ if ( requestCode == 1001 ) {
+
+ int responseCode = data.getIntExtra ( "RESPONSE_CODE", 0 );
+ String purchaseData = data.getStringExtra ( "INAPP_PURCHASE_DATA" );
+ String dataSignature = data.getStringExtra ( "INAPP_DATA_SIGNATURE" );
+
+ ArrayList jsonData = new ArrayList ();
+ jsonData.add ( purchaseData );
+ jsonData.add ( dataSignature );
+ JSONArray jsonArray = new JSONArray ( jsonData );
+
+ synchronized ( Moai.sAkuLock ) {
+
+ AKUNotifyGooglePurchaseResponseReceived ( responseCode, jsonArray.toString ());
+ }
+ }
+ }
+
+ //================================================================//
+ // Google Billing (Android Market) JNI callback methods
+ //================================================================//
+
+ //----------------------------------------------------------------//
+ public static boolean checkInAppSupported () {
+
+ return sInAppSupported;
+ }
+
+ //----------------------------------------------------------------//
+ public static boolean checkSubscriptionSupported () {
+
+ return sSubscriptionSupported;
+ }
+
+ //----------------------------------------------------------------//
+ public static int consumePurchaseSync ( String token ) {
+
+ try {
+
+ int response = sService.consumePurchase ( 3, sActivity.getPackageName (), token );
+ return response;
+
+ } catch ( RemoteException e ) {
+
+ e.printStackTrace ();
+ }
+
+ return BILLING_RESPONSE_RESULT_ERROR;
+ }
+
+ //----------------------------------------------------------------//
+ public static String getPurchasedProducts ( int productType, String continuation ) {
+
+ try {
+
+ String type = ( productType == 0 ) ? PURCHASE_TYPE_INAPP : PURCHASE_TYPE_SUBSCRIPTION;
+ Bundle ownedItems = sService.getPurchases ( 3, sActivity.getPackageName (), type, continuation );
+
+ if ( ownedItems.getInt ( "RESPONSE_CODE" ) == BILLING_RESPONSE_RESULT_OK ) {
+
+ HashMap map = new HashMap < String, JSONArray > ();
+
+ ArrayList ownedSkus = ownedItems.getStringArrayList ( "INAPP_PURCHASE_ITEM_LIST" );
+ if ( ownedSkus != null ) {
+
+ JSONArray skus = new JSONArray ( ownedSkus );
+ map.put ( "ownedSkus", skus );
+ }
+
+ ArrayList purchaseData = ownedItems.getStringArrayList ( "INAPP_PURCHASE_DATA_LIST" );
+ if ( purchaseData != null ) {
+
+ JSONArray dataArray = new JSONArray ();
+ for ( Object dataLine : purchaseData ) {
+
+ try {
+ JSONObject obj = new JSONObject (( String )dataLine );
+ dataArray.put ( obj );
+ } catch ( JSONException e ) {
+ e.printStackTrace ();
+ }
+ }
+ map.put ( "purchaseData", dataArray );
+ }
+
+ ArrayList purchaseSigs = ownedItems.getStringArrayList ( "INAPP_DATA_SIGNATURE" );
+ if ( purchaseSigs != null ) {
+
+ JSONArray sigs = new JSONArray ( purchaseSigs );
+ map.put ( "purchaseSigs", sigs );
+ }
+
+ JSONObject json = new JSONObject ( map );
+ String continuationToken = ownedItems.getString ( "INAPP_CONTINUATION_TOKEN" );
+ try { json.put ( "continuationToken", continuationToken ); } catch ( JSONException e ) { e.printStackTrace (); }
+ return json.toString ();
+ }
+
+ } catch ( RemoteException e ) {
+
+ e.printStackTrace ();
+ }
+
+ return "";
+ }
+
+ //----------------------------------------------------------------//
+ public static int purchaseProduct ( String sku, int productType, String devPayload ) {
+
+ try {
+
+ String type = ( productType == 0 ) ? PURCHASE_TYPE_INAPP : PURCHASE_TYPE_SUBSCRIPTION;
+ Bundle buyIntentBundle = sService.getBuyIntent ( 3, sActivity.getPackageName (), sku, type, devPayload );
+
+ if ( buyIntentBundle.getInt ( "RESPONSE_CODE" ) == BILLING_RESPONSE_RESULT_OK ) {
+
+ PendingIntent pendingIntent = buyIntentBundle.getParcelable ( "BUY_INTENT" );
+ sActivity.startIntentSenderForResult ( pendingIntent.getIntentSender (), 1001, new Intent (), Integer.valueOf ( 0 ), Integer.valueOf ( 0 ), Integer.valueOf ( 0 ));
+ }
+
+ return buyIntentBundle.getInt ( "RESPONSE_CODE" );
+
+ } catch ( Exception e ) {
+
+ e.printStackTrace ();
+ }
+
+ return BILLING_RESPONSE_RESULT_ERROR;
+ }
+
+ //----------------------------------------------------------------//
+ public static String requestProductsSync ( String [] skus, int productType ) {
+
+ try {
+
+ ArrayList skuList = new ArrayList ();
+ for ( String sku : skus ) {
+
+ skuList.add ( sku );
+ }
+
+ Bundle querySkus = new Bundle ();
+ querySkus.putStringArrayList ( "ITEM_ID_LIST", skuList );
+ String type = ( productType == 0 ) ? PURCHASE_TYPE_INAPP : PURCHASE_TYPE_SUBSCRIPTION;
+ Bundle skuDetails = sService.getSkuDetails ( 3, sActivity.getPackageName (), type, querySkus );
+
+ //convert to json string
+ if ( skuDetails.getInt ( "RESPONSE_CODE" ) == BILLING_RESPONSE_RESULT_OK ) {
+
+ ArrayList responseList = skuDetails.getStringArrayList ( "DETAILS_LIST" );
+ JSONArray jsResponse = new JSONArray ( responseList );
+ return jsResponse.toString ();
+ }
+
+ } catch ( RemoteException e ) {
+
+ e.printStackTrace ();
+ }
+
+ return "";
+ }
+}
View
318 src/moaiext-android/MOAIBillingAndroid.cpp
@@ -17,6 +17,21 @@ extern JavaVM* jvm;
//================================================================//
//----------------------------------------------------------------//
+cc8* MOAIBillingAndroid::_luaParseTable ( lua_State* L, int idx ) {
+
+ switch ( lua_type ( L, idx )) {
+
+ case LUA_TSTRING: {
+
+ cc8* str = lua_tostring ( L, idx );
+ return str;
+ }
+ }
+
+ return NULL;
+}
+
+//----------------------------------------------------------------//
/** @name checkBillingSupported
@text Check to see if the currently selected billing provider is available.
@@ -316,6 +331,287 @@ int MOAIBillingAndroid::_setPublicKey ( lua_State* L ) {
return 0;
}
+// Google Play In App Biling v3: TODO - make this meld with existing interface better...
+
+//----------------------------------------------------------------//
+/** @name checkInAppSupported
+ @text Check to see if the device can get in app billing
+
+ @out boolean success
+*/
+int MOAIBillingAndroid::_checkInAppSupported ( lua_State* L ) {
+
+ MOAILuaState state ( L );
+
+ JNI_GET_ENV ( jvm, env );
+
+ jclass billing = env->FindClass ( "com/ziplinegames/moai/MoaiGoogleBilling" );
+ if ( billing == NULL ) {
+
+ USLog::Print ( "MOAIBillingAndroid: Unable to find java class %s", "com/ziplinegames/moai/MoaiGoogleBilling" );
+ } else {
+
+ jmethodID checkInAppSupported = env->GetStaticMethodID ( billing, "checkInAppSupported", "()Z" );
+ if ( checkInAppSupported == NULL ) {
+
+ USLog::Print ( "MOAIBillingAndroid: Unable to find static java method %s", "checkInAppSupported" );
+ } else {
+
+ jboolean jsuccess = ( jboolean )env->CallStaticBooleanMethod ( billing, checkInAppSupported );
+
+ lua_pushboolean ( state, jsuccess );
+ return 1;
+ }
+ }
+
+ lua_pushboolean ( state, false );
+ return 1;
+}
+
+//----------------------------------------------------------------//
+/** @name checkSubscriptionSupported
+ @text Check to see if the device can get subscription billing
+
+ @out boolean success
+*/
+int MOAIBillingAndroid::_checkSubscriptionSupported ( lua_State* L ) {
+
+ MOAILuaState state ( L );
+
+ JNI_GET_ENV ( jvm, env );
+
+ jclass billing = env->FindClass ( "com/ziplinegames/moai/MoaiGoogleBilling" );
+ if ( billing == NULL ) {
+
+ USLog::Print ( "MOAIBillingAndroid: Unable to find java class %s", "com/ziplinegames/moai/MoaiGoogleBilling" );
+ } else {
+
+ jmethodID checkSubscriptionSupported = env->GetStaticMethodID ( billing, "checkSubscriptionSupported", "()Z" );
+ if ( checkSubscriptionSupported == NULL ) {
+
+ USLog::Print ( "MOAIBillingAndroid: Unable to find static java method %s", "checkSubscriptionSupported" );
+ } else {
+
+ jboolean jsuccess = ( jboolean )env->CallStaticBooleanMethod ( billing, checkSubscriptionSupported );
+
+ lua_pushboolean ( state, jsuccess );
+ return 1;
+ }
+ }
+
+ lua_pushboolean ( state, false );
+ return 1;
+}
+
+//----------------------------------------------------------------//
+/** @name consumePurchaseSync
+ @text Consumes a purchase
+
+ @in string token
+ @out nil
+*/
+int MOAIBillingAndroid::_consumePurchaseSync ( lua_State* L ) {
+
+ MOAILuaState state ( L );
+
+ cc8* token = lua_tostring ( state, 1 );
+
+ JNI_GET_ENV ( jvm, env );
+ JNI_GET_JSTRING ( token, jtoken );
+
+ jclass billing = env->FindClass ( "com/ziplinegames/moai/MoaiGoogleBilling" );
+ if ( billing == NULL ) {
+
+ USLog::Print ( "MOAIBillingAndroid: Unable to find java class %s", "com/ziplinegames/moai/MoaiGoogleBilling" );
+ } else {
+
+ jmethodID consumePurchaseSync = env->GetStaticMethodID ( billing, "consumePurchaseSync", "(Ljava/lang/String;)I" );
+ if ( consumePurchaseSync == NULL ) {
+
+ USLog::Print ( "MOAIBillingAndroid: Unable to find static java method %s", "consumePurchaseSync" );
+ } else {
+
+ jint result = ( jint )env->CallStaticIntMethod ( billing, consumePurchaseSync, jtoken );
+ lua_pushinteger ( state, result );
+ return 1;
+ }
+ }
+
+ lua_pushnumber ( state, BILLINGV3_RESPONSE_RESULT_ERROR );
+ return 1;
+}
+
+//----------------------------------------------------------------//
+/** @name getPurchasedProducts
+ @text Gets the user's purchased products
+
+ @in int type
+ @opt string continuation
+ @out string json string of products
+*/
+int MOAIBillingAndroid::_getPurchasedProducts ( lua_State* L ) {
+
+ MOAILuaState state ( L );
+
+ JNI_GET_ENV ( jvm, env );
+
+ // get type
+ int type = lua_tointeger ( state, 1 );
+ cc8* continuation = lua_tostring ( state, 2 );
+ JNI_GET_JSTRING ( continuation, jcontinuation );
+
+ jclass billing = env->FindClass ( "com/ziplinegames/moai/MoaiGoogleBilling" );
+ if ( billing == NULL ) {
+
+ USLog::Print ( "MOAIBillingAndroid: Unable to find java class %s", "com/ziplinegames/moai/MoaiGoogleBilling" );
+ } else {
+
+ jmethodID getPurchasedProducts = env->GetStaticMethodID ( billing, "getPurchasedProducts", "(ILjava/lang/String;)Ljava/lang/String;" );
+ if ( getPurchasedProducts == NULL ) {
+
+ USLog::Print ( "MOAIBillingAndroid: Unable to find static java method %s", "getPurchasedProducts" );
+ } else {
+
+ jstring jresult = ( jstring )env->CallStaticObjectMethod ( billing, getPurchasedProducts, type, jcontinuation );
+
+ JNI_GET_CSTRING ( jresult, result );
+ lua_pushstring ( state, result );
+ JNI_RELEASE_CSTRING ( jresult, result );
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+//----------------------------------------------------------------//
+/** @name purchaseProduct
+ @text Starts a purchase intent for the desired product
+
+ @in string sku
+ @in int type
+ @opt string devPayload
+ @out nil
+*/
+int MOAIBillingAndroid::_purchaseProduct ( lua_State* L ) {
+
+ MOAILuaState state ( L );
+
+ cc8* sku = lua_tostring ( state, 1 );
+ int type = lua_tointeger ( state, 2 );
+ cc8* devPayload = lua_tostring ( state, 3 );
+
+ JNI_GET_ENV ( jvm, env );
+ JNI_GET_JSTRING ( sku, jsku );
+ JNI_GET_JSTRING ( devPayload, jdevPayload );
+
+ jclass billing = env->FindClass ( "com/ziplinegames/moai/MoaiGoogleBilling" );
+ if ( billing == NULL ) {
+
+ USLog::Print ( "MOAIBillingAndroid: Unable to find java class %s", "com/ziplinegames/moai/MoaiGoogleBilling" );
+ } else {
+
+ jmethodID purchaseProduct = env->GetStaticMethodID ( billing, "purchaseProduct", "(Ljava/lang/String;ILjava/lang/String;)I" );
+ if ( purchaseProduct == NULL ) {
+
+ USLog::Print ( "MOAIBillingAndroid: Unable to find static java method %s", "purchaseProduct" );
+ } else {
+
+ jint result = ( jint )env->CallStaticIntMethod ( billing, purchaseProduct, jsku, type, jdevPayload );
+ lua_pushinteger ( state, result );
+ return 1;
+ }
+ }
+
+ lua_pushnumber ( state, BILLINGV3_RESPONSE_RESULT_ERROR );
+ return 1;
+}
+
+//----------------------------------------------------------------//
+/** @name requestProductsSync
+ @text Gets the products from Google Play for the current app
+
+ @in table skus
+ @in int type
+ @out string json string of products
+*/
+int MOAIBillingAndroid::_requestProductsSync ( lua_State* L ) {
+
+ MOAILuaState state ( L );
+
+ JNI_GET_ENV ( jvm, env );
+
+ //read skus from lua table
+ jobjectArray jskus = NULL;
+
+ if ( state.IsType ( 1, LUA_TTABLE )) {
+
+ int numEntries = 0;
+ for ( int key = 1; ; ++key ) {
+
+ state.GetField ( 1, key );
+ cc8* value = _luaParseTable ( state, -1 );
+ lua_pop ( state, 1 );
+
+ if ( !value ) {
+
+ numEntries = key - 1;
+ break;
+ }
+ }
+
+ jskus = env->NewObjectArray ( numEntries, env->FindClass( "java/lang/String" ), 0 );
+ for ( int key = 1; ; ++key ) {
+
+ state.GetField ( 1, key );
+ cc8* value = _luaParseTable ( state, -1 );
+ lua_pop ( state, 1 );
+
+ if ( value ) {
+
+ JNI_GET_JSTRING ( value, jvalue );
+ env->SetObjectArrayElement ( jskus, key - 1, jvalue );
+ }
+ else {
+
+ break;
+ }
+ }
+ }
+
+ if ( jskus == NULL ) {
+
+ jskus = env->NewObjectArray ( 0, env->FindClass( "java/lang/String" ), 0 );
+ }
+
+ // get type
+ int type = lua_tointeger ( state, 2 );
+
+ jclass billing = env->FindClass ( "com/ziplinegames/moai/MoaiGoogleBilling" );
+ if ( billing == NULL ) {
+
+ USLog::Print ( "MOAIBillingAndroid: Unable to find java class %s", "com/ziplinegames/moai/MoaiGoogleBilling" );
+ } else {
+
+ jmethodID requestProductsSync = env->GetStaticMethodID ( billing, "requestProductsSync", "([Ljava/lang/String;I)Ljava/lang/String;" );
+ if ( requestProductsSync == NULL ) {
+
+ USLog::Print ( "MOAIBillingAndroid: Unable to find static java method %s", "requestProductsSync" );
+ } else {
+
+ jstring jresult = ( jstring )env->CallStaticObjectMethod ( billing, requestProductsSync, jskus, type );
+
+ JNI_GET_CSTRING ( jresult, result );
+ lua_pushstring ( state, result );
+ JNI_RELEASE_CSTRING ( jresult, result );
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+
//================================================================//
// MOAIBillingAndroid
//================================================================//
@@ -354,6 +650,19 @@ void MOAIBillingAndroid::RegisterLuaClass ( MOAILuaState& state ) {
state.SetField ( -1, "BILLING_PURCHASE_STATE_ITEM_PURCHASED", ( u32 )BILLING_PURCHASE_STATE_ITEM_PURCHASED );
state.SetField ( -1, "BILLING_PURCHASE_STATE_PURCHASE_CANCELED", ( u32 )BILLING_PURCHASE_STATE_PURCHASE_CANCELED );
state.SetField ( -1, "BILLING_PURCHASE_STATE_ITEM_REFUNDED", ( u32 )BILLING_PURCHASE_STATE_ITEM_REFUNDED );
+
+ // Google Play In App Biling v3: TODO - make this meld with existing interface better...
+ state.SetField ( -1, "BILLINGV3_PRODUCT_INAPP", ( u32 )BILLINGV3_PRODUCT_INAPP );
+ state.SetField ( -1, "BILLINGV3_PRODUCT_SUBSCRIPTION", ( u32 )BILLINGV3_PRODUCT_SUBSCRIPTION );
+
+ state.SetField ( -1, "BILLINGV3_RESPONSE_RESULT_OK", ( u32 )BILLINGV3_RESPONSE_RESULT_OK );
+ state.SetField ( -1, "BILLINGV3_RESPONSE_RESULT_USER_CANCELED", ( u32 )BILLINGV3_RESPONSE_RESULT_USER_CANCELED );
+ state.SetField ( -1, "BILLINGV3_RESPONSE_RESULT_BILLING_UNAVAILABLE", ( u32 )BILLINGV3_RESPONSE_RESULT_BILLING_UNAVAILABLE );
+ state.SetField ( -1, "BILLINGV3_RESPONSE_RESULT_ITEM_UNAVAILABLE", ( u32 )BILLINGV3_RESPONSE_RESULT_ITEM_UNAVAILABLE );
+ state.SetField ( -1, "BILLINGV3_RESPONSE_RESULT_DEVELOPER_ERROR", ( u32 )BILLINGV3_RESPONSE_RESULT_DEVELOPER_ERROR );
+ state.SetField ( -1, "BILLINGV3_RESPONSE_RESULT_ERROR", ( u32 )BILLINGV3_RESPONSE_RESULT_ERROR );
+ state.SetField ( -1, "BILLINGV3_RESPONSE_RESULT_ITEM_ALREADY_OWNED", ( u32 )BILLINGV3_RESPONSE_RESULT_ITEM_ALREADY_OWNED );
+ state.SetField ( -1, "BILLINGV3_RESPONSE_RESULT_ITEM_NOT_OWNED", ( u32 )BILLINGV3_RESPONSE_RESULT_ITEM_NOT_OWNED );
luaL_Reg regTable [] = {
{ "checkBillingSupported", _checkBillingSupported },
@@ -364,6 +673,15 @@ void MOAIBillingAndroid::RegisterLuaClass ( MOAILuaState& state ) {
{ "setBillingProvider", _setBillingProvider },
{ "setListener", _setListener },
{ "setPublicKey", _setPublicKey },
+
+ // Google Play In App Biling v3: TODO - make this meld with existing interface better...
+ { "checkInAppSupported", _checkInAppSupported },
+ { "checkSubscriptionSupported", _checkSubscriptionSupported },
+ { "consumePurchaseSync", _consumePurchaseSync },
+ { "getPurchasedProducts", _getPurchasedProducts },
+ { "purchaseProduct", _purchaseProduct },
+ { "requestProductsSync", _requestProductsSync },
+
{ NULL, NULL }
};
View
27 src/moaiext-android/MOAIBillingAndroid.h
@@ -39,6 +39,8 @@
class MOAIBillingAndroid :
public MOAIGlobalClass < MOAIBillingAndroid, MOAILuaObject > {
private:
+
+ static cc8* _luaParseTable ( lua_State* L, int idx );
//----------------------------------------------------------------//
static int _checkBillingSupported ( lua_State* L );
@@ -49,6 +51,15 @@ class MOAIBillingAndroid :
static int _setBillingProvider ( lua_State* L );
static int _setListener ( lua_State* L );
static int _setPublicKey ( lua_State* L );
+
+ // Google Play In App Biling v3: TODO - make this meld with existing interface better...
+ //----------------------------------------------------------------//
+ static int _checkInAppSupported ( lua_State* L );
+ static int _checkSubscriptionSupported ( lua_State* L );
+ static int _consumePurchaseSync ( lua_State* L );
+ static int _getPurchasedProducts ( lua_State* L );
+ static int _purchaseProduct ( lua_State* L );
+ static int _requestProductsSync ( lua_State* L );
public:
@@ -120,6 +131,22 @@ class MOAIBillingAndroid :
AMAZON_USER_ID_RESTORE_STATUS_SUCCESS,
AMAZON_USER_ID_RESTORE_STATUS_FAILED,
};
+
+ enum {
+ BILLINGV3_PRODUCT_INAPP,
+ BILLINGV3_PRODUCT_SUBSCRIPTION,
+ };
+
+ enum {
+ BILLINGV3_RESPONSE_RESULT_OK = 0,
+ BILLINGV3_RESPONSE_RESULT_USER_CANCELED = 1,
+ BILLINGV3_RESPONSE_RESULT_BILLING_UNAVAILABLE = 3,
+ BILLINGV3_RESPONSE_RESULT_ITEM_UNAVAILABLE = 4,
+ BILLINGV3_RESPONSE_RESULT_DEVELOPER_ERROR = 5,
+ BILLINGV3_RESPONSE_RESULT_ERROR = 6,
+ BILLINGV3_RESPONSE_RESULT_ITEM_ALREADY_OWNED = 7,
+ BILLINGV3_RESPONSE_RESULT_ITEM_NOT_OWNED = 8,
+ };
cc8* mBillingProvider;
MOAILuaRef mListeners [ TOTAL ];
View
72 vs2008/moai-untz/moai-untz.vcproj
@@ -71,7 +71,7 @@
<Tool
Name="VCLinkerTool"
AdditionalDependencies="dsound.lib strmiids.lib opengl32.lib glu32.lib glut32.lib advapi32.lib comctl32.lib oleaut32.lib rpcrt4.lib winmm.lib wldap32.lib ws2_32.lib wsock32.lib iphlpapi.lib psapi.lib"
- AdditionalLibraryDirectories="&quot;..\..\3rdparty\glut-3.7.6-bin&quot;"
+ AdditionalLibraryDirectories="&quot;C:\Program Files (x86)\Microsoft DirectX SDK (June 2010)\Lib\x86&quot;;&quot;..\..\3rdparty\glut-3.7.6-bin&quot;"
IgnoreAllDefaultLibraries="false"
GenerateDebugInformation="true"
SubSystem="1"
@@ -104,11 +104,12 @@
/>
</Configuration>
<Configuration
- Name="Debug|x64"
- OutputDirectory="$(PlatformName)\$(ConfigurationName)"
- IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"
+ Name="Release|Win32"
+ OutputDirectory="..\bin\$(PlatformName)\$(ConfigurationName)\"
+ IntermediateDirectory="$(ConfigurationName)"
ConfigurationType="1"
- CharacterSet="1"
+ CharacterSet="0"
+ WholeProgramOptimization="0"
>
<Tool
Name="VCPreBuildEventTool"
@@ -124,23 +125,19 @@
/>
<Tool
Name="VCMIDLTool"
- TargetEnvironment="3"
/>
<Tool
Name="VCCLCompilerTool"
- Optimization="0"
- AdditionalIncludeDirectories="&quot;..\..\src&quot;"
- PreprocessorDefinitions="WIN32;_CONSOLE;_DEBUG;_BOOL;AKU_DLL"
- MinimalRebuild="true"
- BasicRuntimeChecks="3"
- RuntimeLibrary="3"
+ AdditionalIncludeDirectories="&quot;..\..\3rdparty\openssl-1.0.0d\include-win32&quot;;..\..\src;..\..\src\config;&quot;..\..\src\config-default&quot;;..\..\src\hosts;&quot;..\..\src\moai-lua-5.1.3\src&quot;;&quot;..\..\3rdparty\glut-3.7.6-bin&quot;"
+ PreprocessorDefinitions="WIN32;_CONSOLE;GLUTHOST_USE_LUAEXT;GLUTHOST_USE_PARTICLE_PRESETS;GLUTHOST_USE_UNTZ"
+ RuntimeLibrary="2"
TreatWChar_tAsBuiltInType="false"
ForceConformanceInForLoopScope="false"
RuntimeTypeInfo="false"
UsePrecompiledHeader="0"
WarningLevel="3"
- DebugInformationFormat="3"
- ShowIncludes="false"
+ DebugInformationFormat="0"
+ ForcedIncludeFiles="&quot;zlcore/zl_replace.h&quot;"
/>
<Tool
Name="VCManagedResourceCompilerTool"
@@ -153,16 +150,16 @@
/>
<Tool
Name="VCLinkerTool"
- ShowProgress="0"
- LinkIncremental="2"
- AdditionalLibraryDirectories=""
+ AdditionalDependencies="dsound.lib strmiids.lib opengl32.lib glu32.lib glut32.lib advapi32.lib comctl32.lib oleaut32.lib rpcrt4.lib winmm.lib wldap32.lib ws2_32.lib wsock32.lib iphlpapi.lib psapi.lib"
+ AdditionalLibraryDirectories="&quot;..\..\3rdparty\glut-3.7.6-bin&quot;;&quot;C:\Program Files (x86)\Microsoft DirectX SDK (June 2010)\Lib\x86&quot;"
IgnoreAllDefaultLibraries="false"
GenerateDebugInformation="true"
SubSystem="1"
- EntryPointSymbol=""
+ OptimizeReferences="2"
+ EnableCOMDATFolding="2"
RandomizedBaseAddress="1"
DataExecutionPrevention="0"
- TargetMachine="17"
+ TargetMachine="1"
/>
<Tool
Name="VCALinkTool"
@@ -184,16 +181,15 @@
/>
<Tool
Name="VCPostBuildEventTool"
- CommandLine="xcopy /yr &quot;$(OutDir)\$(TargetFileName)&quot; &quot;..\..\bin\$(PlatformName)\$(ConfigurationName)\&quot;&#x0D;&#x0A;xcopy /yr &quot;$(OutDir)\$(TargetName).pdb&quot; &quot;..\..\bin\$(PlatformName)\$(ConfigurationName)\&quot;&#x0D;&#x0A;"
+ CommandLine="xcopy /yr &quot;..\..\3rdparty\glut-3.7.6-bin\glut32.dll&quot; &quot;$(OutDir)&quot;"
/>
</Configuration>
<Configuration
- Name="Release|Win32"
- OutputDirectory="..\bin\$(PlatformName)\$(ConfigurationName)\"
- IntermediateDirectory="$(ConfigurationName)"
+ Name="Debug|x64"
+ OutputDirectory="$(PlatformName)\$(ConfigurationName)"
+ IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"
ConfigurationType="1"
- CharacterSet="0"
- WholeProgramOptimization="0"
+ CharacterSet="1"
>
<Tool
Name="VCPreBuildEventTool"
@@ -209,19 +205,23 @@
/>
<Tool
Name="VCMIDLTool"
+ TargetEnvironment="3"
/>
<Tool
Name="VCCLCompilerTool"
- AdditionalIncludeDirectories="..\..\src;..\..\src\config;&quot;..\..\src\config-default&quot;;..\..\src\hosts;&quot;..\..\src\moai-lua-5.1.3\src&quot;;&quot;..\..\3rdparty\glut-3.7.6-bin&quot;"
- PreprocessorDefinitions="WIN32;_CONSOLE;GLUTHOST_USE_LUAEXT;GLUTHOST_USE_PARTICLE_PRESETS;GLUTHOST_USE_UNTZ"
- RuntimeLibrary="2"
+ Optimization="0"
+ AdditionalIncludeDirectories="&quot;..\..\src&quot;"
+ PreprocessorDefinitions="WIN32;_CONSOLE;_DEBUG;_BOOL;AKU_DLL"
+ MinimalRebuild="true"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="3"
TreatWChar_tAsBuiltInType="false"
ForceConformanceInForLoopScope="false"
RuntimeTypeInfo="false"
UsePrecompiledHeader="0"
WarningLevel="3"
- DebugInformationFormat="0"
- ForcedIncludeFiles="&quot;zlcore/zl_replace.h&quot;"
+ DebugInformationFormat="3"
+ ShowIncludes="false"
/>
<Tool
Name="VCManagedResourceCompilerTool"
@@ -234,16 +234,16 @@
/>
<Tool
Name="VCLinkerTool"
- AdditionalDependencies="dsound.lib strmiids.lib opengl32.lib glu32.lib glut32.lib advapi32.lib comctl32.lib oleaut32.lib rpcrt4.lib winmm.lib wldap32.lib ws2_32.lib wsock32.lib iphlpapi.lib psapi.lib"
- AdditionalLibraryDirectories="&quot;..\..\3rdparty\glut-3.7.6-bin&quot;"
+ ShowProgress="0"
+ LinkIncremental="2"
+ AdditionalLibraryDirectories=""
IgnoreAllDefaultLibraries="false"
GenerateDebugInformation="true"
SubSystem="1"
- OptimizeReferences="2"
- EnableCOMDATFolding="2"
+ EntryPointSymbol=""
RandomizedBaseAddress="1"
DataExecutionPrevention="0"
- TargetMachine="1"
+ TargetMachine="17"
/>
<Tool
Name="VCALinkTool"
@@ -265,7 +265,7 @@
/>
<Tool
Name="VCPostBuildEventTool"
- CommandLine="xcopy /yr &quot;..\..\3rdparty\glut-3.7.6-bin\glut32.dll&quot; &quot;$(OutDir)&quot;"
+ CommandLine="xcopy /yr &quot;$(OutDir)\$(TargetFileName)&quot; &quot;..\..\bin\$(PlatformName)\$(ConfigurationName)\&quot;&#x0D;&#x0A;xcopy /yr &quot;$(OutDir)\$(TargetName).pdb&quot; &quot;..\..\bin\$(PlatformName)\$(ConfigurationName)\&quot;&#x0D;&#x0A;"
/>
</Configuration>
<Configuration
View
4 vs2008/untz/untz.vcproj
@@ -45,7 +45,7 @@
<Tool
Name="VCCLCompilerTool"
Optimization="0"
- AdditionalIncludeDirectories="..\..\src;..\..\3rdparty\untz\src;..\..\3rdparty\untz\src\native\win;..\..\3rdparty\untz\include;&quot;..\..\3rdparty\libogg-1.2.2\include&quot;;&quot;..\..\3rdparty\libvorbis-1.3.2\include&quot;;&quot;..\..\3rdparty\rtaudio-4.0.8&quot;"
+ AdditionalIncludeDirectories="..\..\src;..\..\3rdparty\untz\src;..\..\3rdparty\untz\src\native\win;..\..\3rdparty\untz\include;&quot;..\..\3rdparty\libogg-1.2.2\include&quot;;&quot;..\..\3rdparty\libvorbis-1.3.2\include&quot;;&quot;..\..\3rdparty\rtaudio-4.0.8\include&quot;;&quot;..\..\3rdparty\rtaudio-4.0.8&quot;"
PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;__WINDOWS_DS__"
MinimalRebuild="true"
BasicRuntimeChecks="3"
@@ -115,7 +115,7 @@
EnableIntrinsicFunctions="true"
FavorSizeOrSpeed="2"
OmitFramePointers="true"
- AdditionalIncludeDirectories="..\..\src;..\..\3rdparty\untz\src;..\..\3rdparty\untz\src\native\win;..\..\3rdparty\untz\include;&quot;..\..\3rdparty\libogg-1.2.2\include&quot;;&quot;..\..\3rdparty\libvorbis-1.3.2\include&quot;;&quot;..\..\3rdparty\rtaudio-4.0.8&quot;"
+ AdditionalIncludeDirectories="..\..\src;..\..\3rdparty\untz\src;..\..\3rdparty\untz\src\native\win;..\..\3rdparty\untz\include;&quot;..\..\3rdparty\libogg-1.2.2\include&quot;;&quot;..\..\3rdparty\libvorbis-1.3.2\include&quot;;&quot;..\..\3rdparty\rtaudio-4.0.8&quot;;&quot;C:\Program Files (x86)\Microsoft DirectX SDK (June 2010)\Include&quot;"
PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;__WINDOWS_DS__"
RuntimeLibrary="2"
UsePrecompiledHeader="0"
Please sign in to comment.
Something went wrong with that request. Please try again.