310 likes | 544 Views
Android In-App Purchases 7 Аппсторов за полчаса. Настя Каримова Разработчик мобильных приложений. Топ приложений в Google Play. Рекламные баннеры . Покупки внутри приложений. к онтент ф ункциональность сервисы. Можно продавать. с onsumable (заклинания, жизни, время)
E N D
Android In-App Purchases7 Аппсторов за полчаса Настя КаримоваРазработчик мобильных приложений
контент • функциональность • сервисы • Можно продавать
сonsumable(заклинания, жизни, время) • non-consumable (уровни, текст книги) • subscriptions (подпискина контент) • Виды инаппов
Вот так выглядит инапп com.game.SKU_THE_BEST_SWORD_EVER
<uses-permission android:name="com.android.vending.BILLING"/> Permission
IabHelperhelper = new IabHelper(context, "your_base_64_public_key"); helper.startSetup(new IabHelper.OnIabSetupFinishedListener() { @Override public void onIabSetupFinished(IabResult result) { if (result.isSuccess()) { //query inventory } else { complain("Billing is not supported."); } } }); Настройка
helper.queryInventoryAsync(true, new IabHelper.QueryInventoryFinishedListener() { @Override public void onQueryInventoryFinished(IabResultresult, Inventory inventory) { if (result.isFailure()) { complain(String.format("queryInventory failed:%s", result)); } else { //consume if not consumed //update UI } } }); Запрашиваем инвентарь
final Purchase tipPurchase = inventory.getPurchase(IN_APP_SKU_TIP); if (tipPurchase != null) { helper.consumeAsync(tipPurchase, new IabHelper.OnConsumeFinishedListener() { @Override public void onConsumeFinished(Purchase purchase, IabResultresult) { if (result.isSuccess()) { if (purchase.getSku().equals(IN_APP_SKU_TIP)) { //process it //update UI } } } }); } Выполняем consume
helper.launchPurchaseFlow(this, sku, REQUEST_CODE_PURCHASE_CODE, new IabHelper.OnIabPurchaseFinishedListener() { @Override public void onIabPurchaseFinished(IabResult result, Purchase info) { if (result.isSuccess() && info.getSku().equals(IN_APP_SKU_TIP)) { //consume //update UI } } }); // your code here @Override protected void onActivityResult(intreqCode, intresCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); helper.handleActivityResult(requestCode, resultCode, data); } Покупка
<application> ... <receiver android:name = "com.amazon.inapp.purchasing.ResponseReceiver" > <intent-filter> <action android:name = "com.amazon.inapp.purchasing.NOTIFY" android:permission= "com.amazon.inapp.purchasing.Permission.NOTIFY" /> </intent-filter> </receiver> ... </application> В манифесте
public class MyPurchasingObserver extends BasePurchasingObserver { private static final String TAG = "IAPPurchasingObserver"; public MyPurchasingObserver(Activity iapActivity) { super(iapActivity); } public void onSdkAvailable(final booleanisSandboxMode) {} public void onGetUserIdResponse(final GetUserIdResponse response) {} public void onItemDataResponse(final ItemDataResponse response) {} public void onPurchaseResponse(final PurchaseResponse response) {} public void onPurchaseUpdatesResponse( final PurchaseUpdatesResponse response) {} } Purchasing observer
public class IAPActivity extends Activity { ... protected void onCreate(Bundle savedInstanceState) { ... PurchasingManager.registerObserver(new MyPurchasingObserver(this)); } ... } Регистрируем observer
PurchasingManager.initiatePurchaseUpdatesRequest(getPersistedOffset());PurchasingManager.initiatePurchaseUpdatesRequest(getPersistedOffset()); public class MyPurchasingObserver extends BasePurchasingObserver { ... public void onPurchaseUpdatesResponse( final PurchaseUpdatesResponse response) { // No implementation required when dealing solely // with consumables. } ... } Запрашиваем инвентарь
public class IAPActivity extends Activity { // ... private void initiatePurchase() { String requestId = PurchasingManager.initiatePurchaseRequest ("com.amazon.example.iap.consumable"); } // ... } public class MyPurchasingObserver extends BasePurchasingObserver { ... public void onPurchaseResponse(PurchaseResponse response) { final PurchaseRequestStatus status = response .getPurchaseRequestStatus(); if (status == PurchaseResponse.PurchaseRequestStatus.SUCCESSFUL) { } } ... } Процесс покупки
<!--all stores--> <uses-permission android:name="android.permission.INTERNET"/> <!--Google Play--> <uses-permission android:name="com.android.vending.BILLING" /> <!--Amazon--> <uses-permission android:name="com.sec.android.iap.permission.BILLING" /> <!--Samsung Apps--> <uses-permission android:name="com.sec.android.iap.permission.BILLING" /> <!--Open Store--> <uses-permission android:name="org.onepf.openiab.permission.BILLING" /> <!--T-Store and Fortumo--> <uses-permission android:name="android.permission.RECEIVE_SMS"/> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/> <uses-permission android:name="android.permission.READ_PHONE_STATE" /> <!--T-Store--> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> <uses-permission android:name="com.tmoney.vending.INBILLING" /> <permission android:name="com.tmoney.vending.INBILLING" /> <!--Fortumo--> <uses-permission android:name="android.permission.SEND_SMS" /> Permissions
МаппингSKU OpenIabHelper.mapSku(SKU_PREMIUM, OpenIabHelper.NAME_AMAZON, "org.onepf.trivialdrive.amazon.premium"); OpenIabHelper.mapSku(SKU_PREMIUM, OpenIabHelper.NAME_TSTORE, "tstore_sku_premium"); OpenIabHelper.mapSku(SKU_PREMIUM, OpenIabHelper.NAME_SAMSUNG, "100000100696/000001003746"); OpenIabHelper.mapSku(SKU_PREMIUM, "com.yandex.store", "org.onepf.trivialdrive.premium"); OpenIabHelper.mapSku(SKU_GAS, OpenIabHelper.NAME_AMAZON, "org.onepf.trivialdrive.amazon.gas"); OpenIabHelper.mapSku(SKU_GAS, OpenIabHelper.NAME_SAMSUNG, "100000100696/000001003744"); OpenIabHelper.mapSku(SKU_GAS, "com.yandex.store", "org.onepf.trivialdrive.gas"); OpenIabHelper.mapSku(SKU_INFINITE_GAS, OpenIabHelper.NAME_AMAZON, "org.onepf.trivialdrive.amazon.infinite_gas"); OpenIabHelper.mapSku(SKU_INFINITE_GAS, OpenIabHelper.NAME_SAMSUNG, "100000100696/000001003747"); OpenIabHelper.mapSku(SKU_INFINITE_GAS, "com.yandex.store", "org.onepf.trivialdrive.infinite_gas");
OpenIabHelper.Options options = new OpenIabHelper.Options(); Map<String, String> storeKeys = new HashMap<String, String>(); storeKeys.put(OpenIabHelper.NAME_GOOGLE, googleBase64EncodedPublicKey); /*storeKeys.put(OpenIabHelper.NAME_AMAZON, "Unavailable. Amazon doesn't support RSA verification. So this mapping is not needed"); */ /* storeKeys.put(OpenIabHelper.NAME_SAMSUNG,"Unavailable. SamsungApps doesn't support RSA verification. So this mapping is not needed"); */ storeKeys.put(OpenIabHelper.NAME_YANDEX, YANDEX_PUBLIC_KEY); options.storeKeys= storeKeys; options.checkInventory = true; options.prefferedStoreNames = ... options.availableStores = ... Опции
OpenIabHelperhelper = new OpenIabHelper(context, options); helper.startSetup(new IabHelper.OnIabSetupFinishedListener() { @Override public void onIabSetupFinished(IabResult result) { if (result.isSuccess()) { //query inventory } else { complain("Billing is not supported."); } } }); Настройка
helper.queryInventoryAsync(true, new IabHelper.QueryInventoryFinishedListener() { @Override public void onQueryInventoryFinished(IabResultresult, Inventory inventory) { if (result.isFailure()) { complain(String.format("queryInventory failed: %s”, result)); } else { //consume if not consumed //update UI } } }); Запрашиваем инвентарь
final Purchase tipPurchase = inventory.getPurchase(IN_APP_SKU_TIP); if (tipPurchase != null) { helper.consumeAsync(tipPurchase, newIabHelper.OnConsumeFinishedListener() { @Override public void onConsumeFinished(Purchase purchase, IabResultresult) { if (result.isSuccess()) { if (purchase.getSku().equals(IN_APP_SKU_TIP)) { //process it //update UI } } } }); } Выполняем consume
helper.launchPurchaseFlow(this, sku, REQUEST_CODE_PURCHASE_CODE, new IabHelper.OnIabPurchaseFinishedListener() { @Override public void onIabPurchaseFinished(IabResult result, Purchase info) { if (result.isSuccess() &&info.getSku().equals(IN_APP_SKU_TIP)) { //consume //update UI } } }); // your code here @Override protected void onActivityResult(intreqCode, intresCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); helper.handleActivityResult(requestCode, resultCode, data); } Покупка
public static booleanverifyPurchase(String base64PublicKey, String signedData, String signature) { if (TextUtils.isEmpty(signedData) ||TextUtils.isEmpty(base64PublicKey) || TextUtils.isEmpty(signature)) { Log.e(TAG, "Purchaseverificationfailed: missing data."); return false; } PublicKeykey = Security.generatePublicKey(base64PublicKey); returnSecurity.verify(key, signedData, signature); } // Unique OpenIAB feature =) Options opts = new Options(); opts.verifyMode = Options.VERIFY_SKIP; mHelper = new OpenIabHelper(context, opts); Код верификации
One Platform Foundation www.onepf.org akarimova@onepf.org github.com/onepf/OpenIAB github.com/onepf/AppDF