ã¿ãªããããã«ã¡ã¯ïŒ æè¿ãè«æ±æžããµãŒãã¹ã«çµ±åããã¿ã¹ã¯ã«çŽé¢ããŸãããåœåã¯ã¿ã¹ã¯ãããªãåçŽã«èŠããŸãããããã®çµæã1ãæã«ãããæéã®ç 究ãç¥çµè³ªãçºèŠããããŸããã ãã®çµæãèšå€§ãªéã®ããã¥ã¡ã³ããããã«ãé¢ããããGoogleã§ã®åçŽãªã¯ãšãªã§ã¯ãã¹ãŠãèŠã€ããããã§ã¯ãªããšããç解ãåŸãããŸããïŒãŸããããã¥ã¡ã³ãã«ãã£ãŠã¯ãŸã£ããã®ãã³ã»ã³ã¹ããããŸãã
ãã®çµæãGoogle Playããã®èª²éããµãŒãã¹ã«æ£åžžã«çµ±åããããµãŒããŒåŽã§ã®è³Œå ¥ãšãµãã¹ã¯ãªãã·ã§ã³ã®æ€èšŒãæ©èœããŸãã é¢çœããªã£ã人-ãããããkatïŒããã§ã¯ãGoogle Play管çã³ã³ãœãŒã«ã§ã®è³Œå ¥ã®ç»é²ãããããã¯ãšã³ãã§ã®ãµãã¹ã¯ãªãã·ã§ã³ã®æäœãŸã§ããã¹ãŠã®è©³çŽ°ãªèª¬æããããŸãã
æ£è ã«ã€ããŠç°¡åã«èª¬æããŸãã Google Play In-App Billing V3ãšã¯ã©ãŠãããŒã¹ã®Android Publisher APIãå解ããŸã ããããã¯ãè³Œå ¥ã®æ€èšŒãšãµãã¹ã¯ãªãã·ã§ã³ã§ã®äœæ¥ã®äž¡æ¹ã«åœ¹ç«ã¡ãŸãã ãŸãã Google Play Management Consoleããã€ãã¹ããŸãã-ãããå¿ èŠã§ãã
ãªããããå¿ èŠãªã®ã§ããïŒ
ã¯ã©ã€ã¢ã³ããµãŒããŒã¢ããªã±ãŒã·ã§ã³ã䜿çšããŠããå ŽåããµãŒããŒã§æ€èšŒãè¡ããªããšãèäœæš©äŸµå®³ã«å¯Ÿããä¿è·ãæäŸã§ããŸããã ãŸãããµãŒããŒäžã®è³Œå ¥ã®ããžã¿ã«çœ²åãç°¡åã«æ€èšŒã§ããŸãããAndroid Publisher APIã¡ãœãããžã®ãªã¯ãšã¹ãã«ã¯ããã€ãã®è¿œå æ©èœããããŸãã ãŸãããŠãŒã¶ãŒã®ããã€ã¹ãåç §ããã«ãã€ã§ãè³Œå ¥ãŸãã¯ãµãã¹ã¯ãªãã·ã§ã³ã«é¢ããæ å ±ãååŸã§ããŸãã次ã«ããµãã¹ã¯ãªãã·ã§ã³ã«é¢ãããã詳现ãªæ å ±ãååŸããŠç®¡çïŒãã£ã³ã»ã«ã延æãªã©ïŒã§ããŸãã ããšãã°ã次ã®æ¯æãã®æ¥ä»ãGoogle Playãã¥ãŒãžãã¯ã®ããã«è¡šç€ºããå ŽåïŒ
ãã®åŸãAndroid Publisher APIããªã¯ãšã¹ãããããšã§ã®ã¿ååŸã§ããŸãã
è«æ±ãçµ±åãããšãã®å®å šãªãããŒã¯æ¬¡ã®ãšããã§ãã
1. Google Playã³ã³ãœãŒã«ã§ã¢ããªã±ãŒã·ã§ã³ãç»é²ããè²·ãç©ãªã¹ããäœæããŸãã
2.ã¢ãã€ã«ã¢ããªã±ãŒã·ã§ã³ã§ã®Androidã¢ããªå 課éã®çµ±åã
3.ãµãŒããŒã§ã®è³Œå ¥ãšãµãã¹ã¯ãªãã·ã§ã³ã®æ€èšŒã
ããŒã1ïŒã¢ããªã±ãŒã·ã§ã³ãGoogle Playã³ã³ãœãŒã«ã«ç»é²ããè²·ãç©ãªã¹ããäœæãã
Google Play管çã³ã³ãœãŒã«ã«ã¢ã¯ã»ã¹ã ïŒã¢ã«ãŠã³ãããæã¡ã§ãªãå Žåã¯25ãã«ã§ç»é²ããŠãã ããïŒãæåã®ã¢ããªã±ãŒã·ã§ã³ãäœæããŠãã ããã ã¢ããªã±ãŒã·ã§ã³ãæ¢ã«ç»é²ãããŠããç¬éããå§ããŸãããã
1.ã¢ããªã±ãŒã·ã§ã³ã以åã«ããŠã³ããŒããããŠããªãå Žå-ãªãªãŒã¹èšŒææžã§ã¢ããªã±ãŒã·ã§ã³ã«çœ²åããã¯ããŒãºãã¢ã«ãã¡ãŸãã¯ããŒã¿ãã¹ãã«ã¢ããããŒãããŸãã
ãã¹ãŠã®ã¢ããªã±ãŒã·ã§ã³/ã¢ããªã±ãŒã·ã§ã³/ APK /ã¢ã«ãã¡ïŒããŒã¿ïŒãã¹ã
2.ãã¹ããªã¹ããäœæããéžæãããã¹ãã®çš®é¡ïŒAlphaãŸãã¯BetaïŒã«å¯ŸããŠã¢ã¯ãã£ãã«ããŸãã
3.ãã®ãªã¹ãã«è«æ±ã«ãããã¹ããããGoogleã¢ã«ãŠã³ãã®ã¡ãŒã«ã¢ã«ãŠã³ããè¿œå ããŸãã ããšãã°ãããã€ã¹ã§Google Playã«å ¥åããå人ã®ã¡ãŒã«ã
äžéšã«ãªããã€ã³URLãªã³ã¯ããããŸãããã®ãªã³ã¯ã¯ã課éããã¹ãããïŒããã³èªåèªèº«ãïŒãã¹ãã«åæãããã¹ãŠã®ãŠãŒã¶ãŒã«æž¡ãå¿ èŠããããŸãã ããããªããšãã¢ã«ãã¡çãŸãã¯ããŒã¿çã§è³Œå ¥ã§ããŸããã
4. [èšå®/ã¢ã«ãŠã³ãã®è©³çŽ° ]ã¿ãã«ç§»åããŠã [ ã©ã€ã»ã³ã¹ ãã¹ã ]ã»ã¯ã·ã§ã³ãèŠã€ãã[ ãã¹ãã¢ã¯ã»ã¹ã®ããGmailã¢ã«ãŠã³ã]ãã£ãŒã«ãã«ãåã®æé ãšåãã¡ãŒã«ãè¿œå ããŸãã ããã§ããããã®ã¢ã«ãŠã³ãããã®è³Œå ¥ããã¹ãã§ããŸã-ç¡æã§ãã
æ¯æãæ¹æ³ãè¿œå ããå¿ èŠããããŸã-è³Œå ¥ãã€ã¢ãã°èªäœã«ãããå¿ èŠã«ãªããŸãããã¢ããªã±ãŒã·ã§ã³ã§è³Œå ¥ãã¿ã³ãããã«è¡šç€ºãããå Žåãããã¯ãã¹ãè³Œå ¥ã§ããããšã瀺ãããŸãã
5.ãã¹ãè³Œå ¥ãã¢ããªã±ãŒã·ã§ã³ã«è¿œå ããŸãã ãããè¡ãã«ã¯ã[ ãã¹ãŠã®ã¢ããªã±ãŒã·ã§ã³] / [ ã¢ããªã±ãŒã·ã§ã³ ] / [ ã¢ããªå 補å ]ã«ç§»åãã[ æ°ãã補åãè¿œå ] ãã¯ãªãã¯ããŸãã 1ã€ã®è³Œå ¥ïŒç®¡ç補åïŒãš1ã€ã®ãµãã¹ã¯ãªãã·ã§ã³ïŒãµãã¹ã¯ãªãã·ã§ã³ïŒãè¿œå ã§ããŸãã 補åIDãšããŠã com.example.myapp_testing_inapp1ãšcom.example.myapp_testing_subs1ã®ã¹ã¿ã€ã«ã®äœããããããè³Œå ¥ãšãµãã¹ã¯ãªãã·ã§ã³ã«äœ¿çšã§ããŸããå°ãªããšãååãšèª¬æãè¿œå ãã補åã®äŸ¡æ Œãèšå®ããå©çšå¯èœãªåœãéžæããå¿ èŠããããŸãïŒãã¹ãŠéžæã§ããŸãïŒ ïŒã賌èªããã«ã¯ãæéãéžæãã補åãã¢ã¯ãã£ãåããŸãã ãã®åŸããã°ãããããšå©çšå¯èœã«ãªããŸãã
éèŠïŒã¢ããªã±ãŒã·ã§ã³ãå ¬éããå¿ èŠããããŸãïŒå°ãªããšãã¢ã«ãã¡çãŸãã¯ããŒã¿çã§ïŒãããããªããš ãè³Œå ¥ã§ããŸãã ã
ç°¡åã«è²·ãç©ã®çš®é¡
1.管ç察象補åïŒinappïŒ-1åéãã®è³Œå ¥ã è³Œå ¥åŸããŠãŒã¶ãŒã¯æ°žä¹ ã«è³Œå ¥ã®ææè ã«ãªããŸããããã®ãããªè³Œå ¥ãã䜿çšãïŒæ¶è²»ïŒããããšãã§ããŸã-ããšãã°ãããŒãã¹ãç²åŸããããã§ãã 䜿çšåŸãè³Œå ¥ã¯è¡šç€ºãããªããªããå床äœæã§ããŸãã
2.ãµãã¹ã¯ãªãã·ã§ã³ïŒsubsïŒ-ãµãã¹ã¯ãªãã·ã§ã³ã ã¢ã¯ãã£ããŒã·ã§ã³åŸããŠãŒã¶ãŒã¯äžå®ã®æéã«äžå®ã®åæ°è«æ±ãããŸãã ãŠãŒã¶ãŒãæ¯æãéããµãã¹ã¯ãªãã·ã§ã³ã¯ã¢ã¯ãã£ãã§ãã
è³Œå ¥ãæå¹åããããšãã¢ãã€ã«ã¢ããªã±ãŒã·ã§ã³ã§ãããã«é¢ããæ å ±ïŒååã説æãçŸå°é貚ã§ã®äŸ¡æ ŒïŒãçŽæ¥ååŸããè³Œå ¥ããããšãã§ããŸãã
ããŒã2ïŒAndroidã¢ããªå 課éãã¢ãã€ã«ã¢ããªã±ãŒã·ã§ã³ã«çµ±åãã
å ¬åŒ ææž
ãŸããã¢ããªã±ãŒã·ã§ã³ã§èª²éãµãŒãã¹ãæäœããããã«ããã€ãã®æäœãå®è¡ããŸãã
IInAppBillingService.aidlãã¡ã€ã«ããããžã§ã¯ãã«ã³ããŒããŸãã
å
¬åŒææžã®ç¡æ翻蚳
IInAppBillingService.aidlã¯ãã¢ããªå
課éããŒãžã§ã³3ãšããåãããããã®ã€ã³ã¿ãŒãã§ã€ã¹ãå®çŸ©ããAndroidã€ã³ã¿ãŒãã§ã€ã¹å®çŸ©èšèªïŒAIDLïŒãã¡ã€ã«ã§ãããã®ã€ã³ã¿ãŒãã§ã€ã¹ã䜿çšããŠã IPCåŒã³åºãã䜿çšããŠèª²éãªã¯ãšã¹ããè¡ããŸãã
AIDLãã¡ã€ã«ãååŸããã«ã¯ïŒ
Android SDK ManagerãéããŸã ã
SDKãããŒãžã£ãŒã§ã [ ãšã¯ã¹ãã©]ã»ã¯ã·ã§ã³ãèŠã€ããŠå±éããŸãã
[ Google Play Billing Library]ãéžæããŸã ã
[ ããã±ãŒãžã®ã€ã³ã¹ããŒã«]ãã¯ãªãã¯ããŠãã€ã³ã¹ããŒã«ãå®äºããŸãã
ãããžã§ã¯ãã®src / mainãã©ã«ããŒã«ç§»åãã aidlãšãããã©ã«ããŒãäœæããŸãã
ãã®ãã©ã«ããŒå ã«ã com.android.vending.billingããã±ãŒãžãäœæããŸãã
IInAppBillingService.aidlãã¡ã€ã«ãïŒ anroid-sdkïŒ / extras / google / play_billing /ãã©ã«ããŒããæ°ããäœæãããsrc / main / aidl / com.android.vending.billingããã±ãŒãžã«ã³ããŒããŸã
AIDLãã¡ã€ã«ãååŸããã«ã¯ïŒ
Android SDK ManagerãéããŸã ã
SDKãããŒãžã£ãŒã§ã [ ãšã¯ã¹ãã©]ã»ã¯ã·ã§ã³ãèŠã€ããŠå±éããŸãã
[ Google Play Billing Library]ãéžæããŸã ã
[ ããã±ãŒãžã®ã€ã³ã¹ããŒã«]ãã¯ãªãã¯ããŠãã€ã³ã¹ããŒã«ãå®äºããŸãã
ãããžã§ã¯ãã®src / mainãã©ã«ããŒã«ç§»åãã aidlãšãããã©ã«ããŒãäœæããŸãã
ãã®ãã©ã«ããŒå ã«ã com.android.vending.billingããã±ãŒãžãäœæããŸãã
IInAppBillingService.aidlãã¡ã€ã«ãïŒ anroid-sdkïŒ / extras / google / play_billing /ãã©ã«ããŒããæ°ããäœæãããsrc / main / aidl / com.android.vending.billingããã±ãŒãžã«ã³ããŒããŸã
ãããã§ã¹ãã«ã¢ã¯ã»ã¹èš±å¯ãè¿œå ããŸãã
<uses-permission android:name="com.android.vending.BILLING" />
ãããŠãè³Œå ¥ããå Žæã§ããµãŒãã¹ã«æ¥ç¶ããŸãã
IInAppBillingService inAppBillingService; ServiceConnection serviceConnection = new ServiceConnection() { @Override public void onServiceConnected(ComponentName name, IBinder service) { inAppBillingService = IInAppBillingService.Stub.asInterface(service); } @Override public void onServiceDisconnected(ComponentName name) { inAppBillingService = null; } }; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); Intent serviceIntent = new Intent("com.android.vending.billing.InAppBillingService.BIND"); serviceIntent.setPackage("com.android.vending"); bindService(serviceIntent, serviceConnection, Context.BIND_AUTO_CREATE); ... } @Override public void onDestroy() { super.onDestroy(); if (serviceConnection != null) { unbindService(serviceConnection); } }
ããã§ãè³Œå ¥ã®äœæ¥ãéå§ã§ããŸãã ãµãŒãã¹ããè³Œå ¥ããååã®ãªã¹ããšèª¬æãšäŸ¡æ ŒãååŸããŸãã
class InAppProduct { public String productId; public String storeName; public String storeDescription; public String price; public boolean isSubscription; public int priceAmountMicros; public String currencyIsoCode; public String getSku() { return productId; } String getType() { return isSubscription ? "subs" : "inapp"; } } List<InAppProduct> getInAppPurchases(String type, String... productIds) throws Exception { ArrayList<String> skuList = new ArrayList<>(Arrays.asList(productIds)); Bundle query = new Bundle(); query.putStringArrayList("ITEM_ID_LIST", skuList); Bundle skuDetails = inAppBillingService.getSkuDetails( 3, context.getPackageName(), type, query); ArrayList<String> responseList = skuDetails.getStringArrayList("DETAILS_LIST"); List<InAppProduct> result = new ArrayList<>(); for (String responseItem : responseList) { JSONObject jsonObject = new JSONObject(responseItem); InAppProduct product = new InAppProduct(); // "com.example.myapp_testing_inapp1" product.productId = jsonObject.getString("productId"); // product.storeName = jsonObject.getString("title"); // product.storeDescription = jsonObject.getString("description"); // "0.99USD" product.price = jsonObject.getString("price"); // "true/false" product.isSubscription = jsonObject.getString("type").equals("subs"); // "990000" = x 1000000 product.priceAmountMicros = Integer.parseInt(jsonObject.getString("price_amount_micros")); // USD product.currencyIsoCode = jsonObject.getString("price_currency_code"); result.add(product); } return result; }
ãã®æ¹æ³ã䜿çšãããšãå©çšå¯èœãªè³Œå ¥ã«é¢ããããŒã¿ãããŠã³ããŒãã§ããŸãã
// List<InAppProduct> purchases = getInAppPurchases("inapp", "com.example.myapp_testing_inapp1"); // List<InAppProduct> subscriptions = getInAppPurchases("subs", "com.example.myapp_testing_subs1");
ããã§ãè²·ãç©ãªã¹ããšãããã«é¢ããæ å ±ãã¢ããªã±ãŒã·ã§ã³ããçŽæ¥ååŸã§ããŸãã äŸ¡æ Œã¯ããŠãŒã¶ãŒãæ¯æãé貚ã§ç€ºãããŸãã ããã»ã¹ã®ãµãŒãã¹ã¯GoogleãµãŒããŒããããŒã¿ãããŠã³ããŒãã§ããããããããã®ã¡ãœããã¯ããã¯ã°ã©ãŠã³ãã¹ã¬ããã§åŒã³åºãå¿ èŠããããŸãã ãã®ããŒã¿ã®äœ¿çšæ¹æ³ã¯ãã客æ§ã®è£éã«ãããŸãã åãåã£ããªã¹ãããäŸ¡æ Œãšè£œååã衚瀺ããããã¢ããªã±ãŒã·ã§ã³ãªãœãŒã¹ã§ååãšäŸ¡æ Œãæå®ã§ããŸãã
ä»ããäœããè²·ãæã§ãïŒ
private static final int REQUEST_CODE_BUY = 1234; 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_SERVICE_UNAVAILABLE = 2; 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; public static final int PURCHASE_STATUS_PURCHASED = 0; public static final int PURCHASE_STATUS_CANCELLED = 1; public static final int PURCHASE_STATUS_REFUNDED = 2; public void purchaseProduct(InAppProduct product) throws Exception { String sku = product.getSku(); String type = product.getType(); // // String developerPayload = "12345"; Bundle buyIntentBundle = inAppBillingService.getBuyIntent( 3, context.getPackageName(), sku, type, developerPayload); PendingIntent pendingIntent = buyIntentBundle.getParcelable("BUY_INTENT"); startIntentSenderForResult(pendingIntent.getIntentSender(), REQUEST_CODE_BUY, new Intent(), Integer.valueOf(0), Integer.valueOf(0), Integer.valueOf(0), null); } @Override public void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); if (requestCode == REQUEST_CODE_BUY) { int responseCode = data.getIntExtra("RESPONSE_CODE", -1); if (responseCode == BILLING_RESPONSE_RESULT_OK) { String purchaseData = data.getStringExtra("INAPP_PURCHASE_DATA"); String dataSignature = data.getStringExtra("INAPP_DATA_SIGNATURE"); // readPurchase(purchaseData); } else { // } } } private void readPurchase(String purchaseData) { try { JSONObject jsonObject = new JSONObject(purchaseData); // , null String orderId = jsonObject.optString("orderId"); // "com.example.myapp" String packageName = jsonObject.getString("packageName"); // "com.example.myapp_testing_inapp1" String productId = jsonObject.getString("productId"); // unix-timestamp long purchaseTime = jsonObject.getLong("purchaseTime"); // PURCHASE_STATUS_PURCHASED // PURCHASE_STATUS_CANCELLED // PURCHASE_STATUS_REFUNDED int purchaseState = jsonObject.getInt("purchaseState"); // "12345" String developerPayload = jsonObject.optString("developerPayload"); // , // String purchaseToken = jsonObject.getString("purchaseToken"); // ... } catch (Exception e) { ... } }
dataSignatureã«ã€ããŠãèšããããšæããŸãã æ€èšŒã®äŸã¯ããã«ãããŸãããè³Œå ¥ããµãŒããŒã§æ€èšŒãããå Žåãããã¯è¿œå ã®æé ã§ãã
ãã§ã«å®äºããè³Œå ¥ã«é¢ããæ å ±ãååŸããããšã圹ç«ã€å ŽåããããŸãã
private void readMyPurchases() throws Exception { readMyPurchases("inapp"); // readMyPurchases("subs"); // } private void readMyPurchases(String type) throws Exception { String continuationToken = null; do { Bundle result = inAppBillingService.getPurchases( 3, context.getPackageName(), type, continuationToken); if (result.getInt("RESPONSE_CODE", -1) != 0) { throw new Exception("Invalid response code"); } List<String> responseList = result.getStringArrayList("INAPP_PURCHASE_DATA_LIST"); for (String purchaseData : responseList) { readPurchase(purchaseData); } continuationToken = result.getString("INAPP_CONTINUATION_TOKEN"); } while (continuationToken != null); }
ãããããã¯ã°ã©ãŠã³ãã¹ã¬ããããå®è¡ããå¿ èŠããããŸãã ããã«ããã以åã«è¡ã£ãè³Œå ¥ã®ãªã¹ããè¿ãããŸãã ã¢ã¯ãã£ããªãµãã¹ã¯ãªãã·ã§ã³ã®ãªã¹ããååŸããããšãã§ããŸãã
次ã®ã¹ãããã¯ãè³Œå ¥ã䜿çšããããšã§ãã ããã¯ãããªããè³Œå ¥ã®ããã«ãŠãŒã¶ãŒã«äœããèç©ããããšãæå³ããè³Œå ¥èªäœã¯æ¶ããŠãåã³è³Œå ¥ããããã®ãããªæ©äŒãäžããŸãã
private void consumePurchase(String purchaseToken) throws Exception { int result = inAppBillingService.consumePurchase(GooglePlayBillingConstants.API_VERSION, context.getPackageName(), purchaseToken); if (result == GooglePlayBillingConstants.BILLING_RESPONSE_RESULT_OK) { // ... } else { // ... } }
ãã®åŸãè³Œå ¥ããŒã¿ãèªã¿åãããšãã§ããªããªããŸã-getPurchasesïŒïŒãä»ããŠå©çšã§ããªããªããŸãã
ããã§ã¯ãããã€ã¹åŽã§çŽæ¥è«æ±ã䜿çšããå¯èœæ§ããããŸãã
ããŒã3ïŒãµãŒããŒã§ã®è³Œå ¥ãšãµãã¹ã¯ãªãã·ã§ã³ã®æ€èšŒ
ããã¯ãç§ãæãé·ãæŠã£ãäžã§æãèå³æ·±ãéšåã§ãã ãã¹ãŠã®äŸã¯Javaã§äœæãããGoogleã¯ãµãŒãã¹ãæäœããããã®æ¢è£œã®ã©ã€ãã©ãªãæäŸããŸãã
ä»ã®èšèªã®ã©ã€ãã©ãªãããã§æ€çŽ¢ã§ããŸã ã Google Publisher APIã®ããã¥ã¡ã³ãã¯ãã¡ãã§ããçŸåšã®ã¿ã¹ã¯ã®ã³ã³ããã¹ãã§ã¯ã Purchases.productsãšPurchases.subscriptionsã«èå³ããããŸãã
å®éãç§ãééããäž»ãªåé¡ã¯ãèªèšŒæ¹æ³ã®èª¬æã§ã ã ãŸãã«èª¬æã§ãããããã¯éŠ¬ã®ç¬¬äºèã®ããã«èŠããŸãããåé¡ã¯ãããæ©èœããªãããšã§ã¯ãªãããããç§ãã¡ã®ä»äºã«ãšã£ãŠæ ¹æ¬çã«ééã£ãŠããããšã§ãã ç§ã«ç³ãæããŠã¯ãããªããšããéå®å®¶ãžã®èŠæ±ïŒOAuthã¯ã¯ã©ã€ã¢ã³ããªãœãŒã¹ã§åäœããããã«èšèšãããŠããŸãããã®å Žåãããã¯ãšã³ããµãŒãã¹ã¯ç¬èªã®ã¢ããªã±ãŒã·ã§ã³ããè«æ±ããŒã¿ãèŠæ±ããŸãã
ãããŠãããã§IAMïŒIdenty Access ManagementïŒãå©ãã«ãªããŸãã Google Cloud Consoleã§ãããžã§ã¯ããäœæãã[ èªèšŒæ å ± ]ã¿ãã«ç§»åããŠã[ èªèšŒæ å ±ã®äœæ ] â [ ãµãŒãã¹ã¢ã«ãŠã³ãã㌠]ãéžæããå¿ èŠããããŸã ã
åçã«ç€ºãããã«ããŒã¿ãå ¥åããŸãã
ãµãŒãã¹ã¢ã«ãŠã³ãïŒæ°ãããµãŒãã¹ã¢ã«ãŠã³ã
ãµãŒãã¹ã¢ã«ãŠã³ãåïŒéžæã®ããã®åå
圹å²ïŒéžæããªãã§ãã ããã圌女ã¯ä»ã¯å¿ èŠãããŸãã
ããŒã¿ã€ãïŒJSON
äœæãã¯ãªãã¯ããŸã ã ãµãŒãã¹ã¢ã«ãŠã³ãã«åœ¹å²ããããŸãããšããèŠåãšãšãã«ãŠã£ã³ããŠããããã¢ããããŸã ã åæããŠã ããŒã«ãªãã§äœæãéžæããŸãã ã¢ã«ãŠã³ãã®èªèšŒçšã®ããŒã¿ãå«ãJSONãã¡ã€ã«ãèªåçã«ããŠã³ããŒãããŸãã ãã®ãã¡ã€ã«ãä¿åããŸã-å°æ¥ãGoogleãµãŒãã¹ã«ãã°ã€ã³ããããã«å¿ èŠã«ãªããŸãã
ãã¡ã€ã«äŸ
{ "type": "service_account", "project_id": "project-name", "private_key_id": "1234567890abcdef1234567890abcdef", "private_key": "-----BEGIN PRIVATE KEY-----\XXXXX.....XXXXX\n-----END PRIVATE KEY-----\n", "client_email": "myaccount@project-name.iam.gserviceaccount.com", "client_id": "12345678901234567890", "auth_uri": "https://accounts.google.com/o/oauth2/auth", "token_uri": "https://accounts.google.com/o/oauth2/token", "auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs", "client_x509_cert_url": "https://www.googleapis.com/robot/v1/metadata/x509/myaccount%40project-name.iam.gserviceaccount.com" }
ãããžã§ã¯ãã®[ è³æ Œæ å ± ]ã¿ãã«æ»ãã以äžã®ãµãŒãã¹ã¢ã«ãŠã³ãããŒã®ãªã¹ãã確èªããŸãã å³åŽã«ãã[ãµãŒãã¹ã¢ã«ãŠã³ãã®ç®¡ç ]ãã¿ã³ãã¯ãªãã¯ããŸããã¯ãªãã¯ãããšã以äžã衚瀺ãããŸã
myaccount@project-name.iam.gserviceaccount.com-ããã¯ã¢ã«ãŠã³ãã®IDã§ãã ãããã³ããŒããŠã Google Play Developer Consoleâèšå®âãŠãŒã¶ãŒã¢ã«ãŠã³ããšæš©å©ã«ç§»åã ã æ°ãããŠãŒã¶ãŒãæåŸ ãéžæããŸã ã
ããŒã¿ãå ¥åããŸãã
ã¢ã«ãŠã³ãIDã[ ã¡ãŒã«]ãã£ãŒã«ãã«è²Œãä»ããã¢ããªã±ãŒã·ã§ã³ãè¿œå ããŠã [財åã¬ããŒãã®è¡šç€º]ã®åã«ãã§ãã¯ããŒã¯ãä»ããŸã ã
[æåŸ ç¶ãéä¿¡]ãã¯ãªãã¯ããŸãã ããã§ãJSONãã¡ã€ã«ãæ¿èªãšGoogle APIã«äœ¿çšããŠãã¢ããªã±ãŒã·ã§ã³ã®è³Œå ¥ãšãµãã¹ã¯ãªãã·ã§ã³ã®ããŒã¿ã«ã¢ã¯ã»ã¹ã§ããŸãã
次ã®ã¹ãããã¯ããããžã§ã¯ãã®Google Play Developer APIãã¢ã¯ãã£ãã«ããããšã§ã ã Google Developer Consoleâã©ã€ãã©ãªã«ç§»åãã Google Play Developer APIãæ¢ããŸã ã ãããéãã ãæå¹åããã¯ãªãã¯ããŸãã
æåŸã®ã¹ãããã¯ã Google Play Developer Console-> Settings-> API Accessã«ç§»åããããšã§ãã
ãªã¹ããããããžã§ã¯ããèŠã€ãïŒäžã®å³ã§ã¯Google Play Android Developerã§ããããããžã§ã¯ãã®ååã衚瀺ãããŠããã¯ãã§ãïŒã[ ãªã³ã¯ ]ãã¯ãªãã¯ããŸãã
ãµãŒããŒåŽã®éçºã«ç§»ããŸããã
IAMã¢ã«ãŠã³ãã®ãã©ã€ããŒãããŒã¿ãšãšãã«JSONãã¡ã€ã«ãä¿åããæ¹æ³ã¯ãã客æ§ã®è£éã«ä»»ãããŸãã Google Play Developer APIããããžã§ã¯ãïŒ mavencentral ïŒã«ã€ã³ããŒããããã§ãã¯ãå®è£ ããŸãã
è³Œå ¥ããŒã¿ã¯ãã¢ããªã±ãŒã·ã§ã³ãããµãŒããŒã«éä¿¡ããå¿ èŠããããŸãã ãµãŒããŒã§ã®æ€èšŒã®å®éã®å®è£ ã¯æ¬¡ã®ããã«ãªããŸãã
import com.google.api.client.googleapis.auth.oauth2.GoogleCredential; import com.google.api.client.googleapis.javanet.GoogleNetHttpTransport; import com.google.api.client.http.HttpTransport; import com.google.api.client.json.jackson2.JacksonFactory; import com.google.api.services.androidpublisher.AndroidPublisher; import com.google.api.services.androidpublisher.AndroidPublisherScopes; import com.google.api.services.androidpublisher.model.ProductPurchase; import com.google.api.services.androidpublisher.model.SubscriptionPurchase; import java... public class GooglePlayService { private final Map<String, AndroidPublisher> androidPublishers = new HashMap<>(); private String readCredentialsJson(String packageName) { // JSON- ... } private AndroidPublisher getPublisher(String packageName) throws Exception { if (!androidPublishers.containsKey(packageName)) { String credentialsJson = readCredentialsJson(packageName); InputStream inputStream = new ByteArrayInputStream( credentialsJson.getBytes(StandardCharsets.UTF_8)); HttpTransport transport = GoogleNetHttpTransport.newTrustedTransport(); GoogleCredential credential = GoogleCredential.fromStream(inputStream) .createScoped(Collections.singleton( AndroidPublisherScopes.ANDROIDPUBLISHER)); AndroidPublisher.Builder builder = new AndroidPublisher.Builder( transport, JacksonFactory.getDefaultInstance(), credential); AndroidPublisher androidPublisher = builder.build(); androidPublishers.put(packageName, androidPublisher); } return androidPublishers.get(packageName); } public ProductPurchase getPurchase(String packageName, String productId, String token) throws Exception { AndroidPublisher publisher = getPublisher(packageName); AndroidPublisher.Purchases.Products.Get get = publisher .purchases().products().get(packageName, productId, token); return get.execute(); } public SubscriptionPurchase getSubscription(String packageName, String productId, String token) throws Exception { AndroidPublisher publisher = getPublisher(packageName); AndroidPublisher.Purchases.Subscriptions.Get get = publisher .purchases().subscriptions().get(packageName, productId, token); return get.execute(); } }
ãããã£ãŠãGoogleããè³Œå ¥ã«é¢ããããŒã¿ãçŽæ¥åãåãæ©äŒãåŸãããããã眲åã確èªããå¿ èŠããªããªããŸãã ããã«ããµãã¹ã¯ãªãã·ã§ã³ã®å Žåãã¢ãã€ã«ã¢ããªã±ãŒã·ã§ã³ã®IInAppBilligServiceããçŽæ¥ååŸãããããã¯ããã«å€ãã®æ å ±ãååŸã§ããŸãã
ãªã¯ãšã¹ããã©ã¡ãŒã¿ãšããŠå¿ èŠãªãã®ïŒ
- packageName-ã¢ããªã±ãŒã·ã§ã³ããã±ãŒãžåïŒcom.example.myappïŒ
- productId-補åèå¥åïŒcom.example.myapp_testing_inapp1ïŒ
- token-ã¢ãã€ã«ã¢ããªã±ãŒã·ã§ã³ã§åãåã£ãäžæã®è³Œå
¥ããŒã¯ã³ïŒ
String purchaseToken = jsonObject.getString("purchaseToken");
ProductPurchaseããã³SubscriptionPurchaseã®è©³çŽ°ã¯ããã¥ã¡ã³ãã«èšèŒãããŠããŸããããããã«ã€ããŠã¯è©³ãã説æããŸããã
çµè«ã®ä»£ããã«
ããã¥ã¡ã³ãã«ã¢ã¯ã»ã¹ç®çã§IAMã䜿çšããããšã«ã€ããŠã®èšèããªããããæåã¯ãè«æ±æžããµãŒãã¹ã«çµ±åããäžèŠåçŽãªã¿ã¹ã¯ããããã¥ã¡ã³ããã°ãŒã°ã«ãããã³ç¡åïŒOAuthã ããªãã¯çŸãã ïŒã®æ ã«å€ãããŸããã çå£ã«ã圌ãã¯ããªãã®ãã©ãŠã¶ã§ã¯ãã¯ã¢ãããããURLãæã«å ¥ãããããžã§ã¯ã管çã³ã³ãœãŒã«ã§ãªãã€ã¬ã¯ãã®èµ·æºãè¿œå ããããªããæã§ãµãŒããŒã«è»¢éããå¿ èŠãããã¯ã³ã¿ã€ã ããŒã¯ã³ãååŸããOAuthãããŒå šäœã䜿çšããããšãæäŸããŸãè«æ±ããŒã¿ã«ã¢ã¯ã»ã¹ããŸãã ãªãã¬ãã·ã¥ããŒã¯ã³ã䜿çšããæéããªãå Žåã¯ãæã§æ°ããããŒã¯ã³ãååŸããå¿ èŠãããããšã¯èšããŸã§ããããŸããã åæãã-ããã¯ã人éã®ä»å ¥ãªãã§æ©èœããããã¯ãšã³ããµãŒãã¹ã®å®å šãªãã³ã»ã³ã¹ã®ããã«èãããŸãã
ãã®èšäºã誰ããå°ãã®æéãšç¥çµãç¯çŽããã®ã«åœ¹ç«ã€ããšãé¡ã£ãŠããŸãã