Java tutorial
package jp.app_mart.billing; import java.security.Key; import java.security.KeyFactory; import java.security.spec.KeySpec; import java.security.spec.X509EncodedKeySpec; import java.util.List; import javax.crypto.Cipher; import jp.app_mart.sample.R; import jp.app_mart.service.AppmartInBillingInterface; import org.json.JSONException; import org.json.JSONObject; import android.app.Activity; import android.app.PendingIntent; import android.content.BroadcastReceiver; import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.content.ServiceConnection; import android.os.Bundle; import android.os.Handler; import android.os.IBinder; import android.os.RemoteException; import android.util.Base64; import android.util.Log; /** * appmart??? * appmart??????aild??????? * ??? http://appmart.jp/ */ public class AppmartHelper { //? boolean mDebugLog = false; String mDebugTag = "IabHelper"; //Appmart?? public static final String RESULT_CODE_STRING = "resultCode"; public static final String BILLING_APPMART_PACKAGE_NAME = "jp.app_mart"; public static final String BILLING_APPMART_SERVICE_NAME = "jp.app_mart.service.AppmartInBillingService"; public static final int BILLING_RESPONSE_RESULT_OK = 1; public static final int BILLING_RESPONSE_RESULT_BILLING_UNAVAILABLE = 91; public static final int BILLING_CONFIRM_TRANSACTION_FAILED = 92; public static final int APPMARTHELPER_GET_BUNDLE_FOR_PAYMENT_FAILED = 93; public static final int APPMARTHELPER_SEND_INTENT_FAILED = 94; public static final int APPMARTHELPER_REMOTE_EXCEPTION = 95; public static final int APPMARTHELPER_JSON_EXCEPTION = 96; public static final int APPMARTHELPER_BAD_RESPONSE = 97; public static final int APPMARTHELPER_INTERRUPTED = 98; public static final int APPMARTHELPER_EXCEPTION = 101; // public Context mContext; //??? public String mDeveloperId; public String mLicenseKey; public String mSignatureBase64; public String mAppId; public String resultKey; //aidl???? public AppmartInBillingInterface mService; //???ServiceConnection public ServiceConnection mServiceConn; //? public AppmartReceiver mReceiver; // public boolean mSetupDone = false; // public boolean mAsyncInProgress = false; public String mAsyncOperation = ""; public OnAppmartPurchaseFinishedListener mPurchaseListener; //?? public String mPurchasingItemType; public String mPurchasingSku; /** * Constructor * @param ctx * @param developerId * @param licenseKey * @param base64PublicKey * @param appId */ public AppmartHelper(Context ctx, String developerId, String licenseKey, String base64PublicKey, String appId) { mContext = ctx; mDeveloperId = developerId; mLicenseKey = licenseKey; mSignatureBase64 = base64PublicKey; mAppId = appId; } /** * Debug * @param enable * @param tag */ public void enableDebugLogging(boolean enable, String tag) { mDebugLog = enable; mDebugTag = tag; } public void enableDebugLogging(boolean enable) { mDebugLog = enable; } /** * callback? * {@link #onAppmartSetupFinished}????? */ public interface OnAppmartSetupFinishedListener { public void onAppmartSetupFinished(AppmartResult result); } /** * appmart??? * @param listener Activity?callback */ public void startSetup(final OnAppmartSetupFinishedListener listener) { if (mSetupDone) throw new IllegalStateException(mContext.getString(R.string.already_connected)); mServiceConn = new ServiceConnection() { //? public void onServiceConnected(ComponentName name, IBinder boundService) { mService = AppmartInBillingInterface.Stub.asInterface((IBinder) boundService); mSetupDone = true; if (listener != null) { listener.onAppmartSetupFinished(new AppmartResult(BILLING_RESPONSE_RESULT_OK, mContext.getString(R.string.is_now_connected))); } //????receiver IntentFilter filter = new IntentFilter("appmart_broadcast_return_service_payment"); if (mReceiver == null) mReceiver = new AppmartReceiver(); mContext.registerReceiver(mReceiver, filter); } //? public void onServiceDisconnected(ComponentName name) { logDebug(mContext.getString(R.string.is_now_deconnected)); mService = null; } }; Intent serviceIntent = new Intent(); serviceIntent.setClassName(BILLING_APPMART_PACKAGE_NAME, BILLING_APPMART_SERVICE_NAME); //?appmart???????? if (!mContext.getPackageManager().queryIntentServices(serviceIntent, 0).isEmpty()) { mContext.bindService(serviceIntent, mServiceConn, Context.BIND_AUTO_CREATE); } else { if (listener != null) { listener.onAppmartSetupFinished(new AppmartResult(BILLING_RESPONSE_RESULT_BILLING_UNAVAILABLE, mContext.getString(R.string.appmart_not_installed))); } } } /** * ??? */ public void dispose() { mSetupDone = false; if (mServiceConn != null) { if (mContext != null) { mContext.unregisterReceiver(mReceiver); mReceiver = null; mContext.unbindService(mServiceConn); } mServiceConn = null; mService = null; mPurchaseListener = null; } } /** * ?callback */ public interface OnAppmartPurchaseFinishedListener { public void onAppmartPurchaseFinished(AppmartResult result, Payment info); } /** * ?? * @param act * @param sku * @param requestCode * @param listener */ public void launchPurchaseFlow(final Activity act, final String sku, final int requestCode, final OnAppmartPurchaseFinishedListener listener) { final String itemType = "0"; checkSetupDone("launchPurchaseFlow"); (new Thread(new Runnable() { public void run() { logDebug(mContext.getString(R.string.get_information) + sku); AppmartResult result; try { Context context = mContext.getApplicationContext(); String dataEncrypted = createEncryptedData(sku, mDeveloperId, mLicenseKey, mSignatureBase64); Bundle bundleForPaymentInterface = mService.prepareForBillingService(mAppId, dataEncrypted); if (bundleForPaymentInterface == null) { logError(mContext.getString(R.string.bundle_unreachable)); result = new AppmartResult(APPMARTHELPER_GET_BUNDLE_FOR_PAYMENT_FAILED, mContext.getString(R.string.bundle_unreachable)); if (listener != null) listener.onAppmartPurchaseFinished(result, null); return; } int response = bundleForPaymentInterface.getInt("resultCode"); if (response != BILLING_RESPONSE_RESULT_OK) { logError(mContext.getString(R.string.response_code_error) + response); result = new AppmartResult(response, mContext.getString(R.string.product_not_purchasable)); if (listener != null) listener.onAppmartPurchaseFinished(result, null); return; } // ? resultKey = bundleForPaymentInterface.getString("resultKey"); PendingIntent pIntent = bundleForPaymentInterface.getParcelable("appmart_pending_intent"); mPurchaseListener = listener; mPurchasingItemType = itemType; mPurchasingSku = sku; pIntent.send(context, 0, new Intent()); } catch (RemoteException e) { logError(mContext.getString(R.string.failed_prepare_bill_service)); result = new AppmartResult(APPMARTHELPER_SEND_INTENT_FAILED, mContext.getString(R.string.failed_sending_intent)); if (listener != null) listener.onAppmartPurchaseFinished(result, null); } catch (PendingIntent.CanceledException e) { logError(mContext.getString(R.string.failed_sending_intent)); result = new AppmartResult(APPMARTHELPER_SEND_INTENT_FAILED, mContext.getString(R.string.failed_sending_intent)); if (listener != null) listener.onAppmartPurchaseFinished(result, null); } } })).start(); } /** * Broadcast Receiver * ???? */ private class AppmartReceiver extends BroadcastReceiver { @Override public void onReceive(final Context arg0, final Intent arg1) { (new Thread(new Runnable() { public void run() { AppmartResult result; try { // String resultKeyCurrentStransaction = arg1.getExtras().getString("appmart_result_key"); if (resultKeyCurrentStransaction == null || resultKeyCurrentStransaction.equals(resultKey)) { Thread.sleep(1000); // ? final String transactionId = arg1.getExtras().getString("appmart_service_trns_id"); int res = mService.confirmFinishedTransaction(transactionId, mPurchasingSku, mDeveloperId); if (res != BILLING_RESPONSE_RESULT_OK) { result = new AppmartResult(BILLING_CONFIRM_TRANSACTION_FAILED, "ErrorCode:" + res + " (" + transactionId + ", " + mPurchasingSku + ", " + mDeveloperId + ")"); if (mPurchaseListener != null) mPurchaseListener.onAppmartPurchaseFinished(result, null); return; } String json = mService.getPaymentDetails(transactionId, mPurchasingSku, mDeveloperId); logDebug("Payment details: " + json); Payment payment = new Payment(mPurchasingItemType, mPurchasingSku, json, transactionId); result = new AppmartResult(BILLING_RESPONSE_RESULT_OK, null); if (mPurchaseListener != null) mPurchaseListener.onAppmartPurchaseFinished(result, payment); } } catch (RemoteException e) { result = new AppmartResult(APPMARTHELPER_REMOTE_EXCEPTION, null); if (mPurchaseListener != null) mPurchaseListener.onAppmartPurchaseFinished(result, null); e.printStackTrace(); } catch (JSONException e) { result = new AppmartResult(APPMARTHELPER_JSON_EXCEPTION, null); if (mPurchaseListener != null) mPurchaseListener.onAppmartPurchaseFinished(result, null); e.printStackTrace(); } catch (InterruptedException e) { result = new AppmartResult(APPMARTHELPER_INTERRUPTED, null); if (mPurchaseListener != null) mPurchaseListener.onAppmartPurchaseFinished(result, null); } catch (Exception e) { result = new AppmartResult(APPMARTHELPER_EXCEPTION, null); if (mPurchaseListener != null) mPurchaseListener.onAppmartPurchaseFinished(result, null); } } })).start(); } } /** * * @param querySkuDetails * @param moreSkus * @return * @throws AppmartException */ public AppmartInventory queryInventory(boolean querySkuDetails, List<String> moreSkus) throws AppmartException { return queryInventory(querySkuDetails, moreSkus, null); } public interface QueryAppmartInventoryFinishedListener { public void onQueryInventoryFinished(AppmartResult result, AppmartInventory inv); } /** * thread?? * @param querySkuDetails * @param moreSkus * @param listener */ public void queryInventoryAsync(final List<String> moreSkus, final QueryAppmartInventoryFinishedListener listener) { final Handler handler = new Handler(); checkSetupDone("queryInventory"); flagStartAsync("refresh inventory"); (new Thread(new Runnable() { public void run() { AppmartResult result = new AppmartResult(BILLING_RESPONSE_RESULT_OK, mContext.getString(R.string.inventory_refreshed)); AppmartInventory inv = null; try { inv = queryInventory(true, moreSkus); } catch (AppmartException ex) { result = ex.getResult(); } flagEndAsync(); final AppmartResult result_f = result; final AppmartInventory inv_f = inv; handler.post(new Runnable() { public void run() { listener.onQueryInventoryFinished(result_f, inv_f); } }); } })).start(); } /** * * @param querySkuDetails * @param moreItemSkus * @param moreSubsSkus * @return * @throws AppmartException */ public AppmartInventory queryInventory(boolean querySkuDetails, List<String> moreItemSkus, List<String> moreSubsSkus) throws AppmartException { checkSetupDone("queryInventory"); try { AppmartInventory inv = new AppmartInventory(); if (querySkuDetails) { int r = querySkuDetails(inv, moreItemSkus); if (r != BILLING_RESPONSE_RESULT_OK) { throw new AppmartException(r, mContext.getString(R.string.inventory_refreshed_error)); } } return inv; } catch (RemoteException e) { throw new AppmartException(APPMARTHELPER_REMOTE_EXCEPTION, mContext.getString(R.string.inventory_refreshed_error_remote), e); } catch (JSONException e) { throw new AppmartException(APPMARTHELPER_BAD_RESPONSE, mContext.getString(R.string.inventory_refreshed_error_json), e); } } /** * ????AppmartInventory? * @param inv ? * @param serviceIds ? * @throws RemoteException * @throws JSONException */ int querySkuDetails(AppmartInventory inv, List<String> serviceIds) throws RemoteException, JSONException { logDebug(mContext.getString(R.string.get_inventory)); int response = BILLING_RESPONSE_RESULT_OK; //???? for (String serviceId : serviceIds) { String json = mService.getServiceDetails(mAppId, createEncryptedData(serviceId, mDeveloperId, mLicenseKey, mSignatureBase64)); //JSON? JSONObject o = new JSONObject(json); //?? int tmpResponse = Integer.valueOf(o.optString(RESULT_CODE_STRING)); if (tmpResponse != BILLING_RESPONSE_RESULT_OK) { response = tmpResponse; } ServiceDetails details = new ServiceDetails(json); inv.addServiceDetails(details); } return response; } /** * ? * @param serviceId * @param developId * @param strLicenseKey * @param strPublicKey * @return */ public static String createEncryptedData(String serviceId, String developId, String strLicenseKey, String strPublicKey) { final String SEP_SYMBOL = "&"; StringBuilder infoDataSB = new StringBuilder(); infoDataSB.append(serviceId).append(SEP_SYMBOL); // ?ID infoDataSB.append(developId).append(SEP_SYMBOL); // infoDataSB.append(strLicenseKey); String strEncryInfoData = ""; try { KeyFactory keyFac = KeyFactory.getInstance("RSA"); KeySpec keySpec = new X509EncodedKeySpec(Base64.decode(strPublicKey.getBytes(), Base64.DEFAULT)); Key publicKey = keyFac.generatePublic(keySpec); if (publicKey != null) { Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding"); cipher.init(Cipher.ENCRYPT_MODE, publicKey); byte[] EncryInfoData = cipher.doFinal(infoDataSB.toString().getBytes()); strEncryInfoData = new String(Base64.encode(EncryInfoData, Base64.DEFAULT)); } } catch (Exception ex) { ex.printStackTrace(); strEncryInfoData = ""; Log.e("AppmartHelper", "?"); } return strEncryInfoData.replaceAll("(\\r|\\n)", ""); } /** * ?????? * @param operation */ void checkSetupDone(String operation) { if (!mSetupDone) { throw new IllegalStateException("?????" + operation); } } /** * * @param operation */ void flagStartAsync(String operation) { if (mAsyncInProgress) throw new IllegalStateException("Can't start async operation (" + operation + ") because another async operation(" + mAsyncOperation + ") is in progress."); mAsyncOperation = operation; mAsyncInProgress = true; logDebug("Starting async operation: " + operation); } /** * */ void flagEndAsync() { logDebug("Ending async operation: " + mAsyncOperation); mAsyncOperation = ""; mAsyncInProgress = false; } /** * ?? * @param code * @return */ public static String getResponseDesc(int code) { switch (code) { case BILLING_CONFIRM_TRANSACTION_FAILED: return "Confirm transaction failed"; case APPMARTHELPER_REMOTE_EXCEPTION: return "Remote exception"; case APPMARTHELPER_JSON_EXCEPTION: return "JSON exception"; case APPMARTHELPER_INTERRUPTED: return "Thread error"; default: return "tmp message"; } } void logDebug(String msg) { if (mDebugLog) Log.d(mDebugTag, msg); } void logError(String msg) { Log.e(mDebugTag, "In-app billing error: " + msg); } void logWarn(String msg) { Log.w(mDebugTag, "In-app billing warning: " + msg); } }