Programming
Development of mobile applications
Development for Android
Mobile applications monetization

Покупки в Android приложении — Play Billing Library

From Sandbox
image

И как это до сих пор на Хабре нет статьи об этом? Не дело, надо исправлять.

Есть 2 способа добавить In-App покупки в Android-приложение — старый и новый. До 2017 года все пользовались библиотекой от anjlab, но с июня 2017 года ситуация изменилась, Google выпустила собственную библиотеку для внутренних покупок и подписок — Play Billing Library. Сейчас последний считается стандартом.

Play Billing Library это очень просто.

Подключите зависимость.

implementation 'com.android.billingclient:billing:1.2'

Добавьте разрешение в манифесте.

<uses-permission android:name="com.android.vending.BILLING"/>

Создайте инстанс BillingClient и начните соединение.


private BillingClient mBillingClient;
...
mBillingClient = BillingClient.newBuilder(this).setListener(new PurchasesUpdatedListener() {
    @Override
    public void onPurchasesUpdated(int responseCode, @Nullable List<Purchase> purchases) {
        if (responseCode == BillingClient.BillingResponse.OK && purchases != null) {
            //сюда мы попадем когда будет осуществлена покупка

        }
    }
}).build();
mBillingClient.startConnection(new BillingClientStateListener() {
    @Override
    public void onBillingSetupFinished(@BillingClient.BillingResponse int billingResponseCode) {
        if (billingResponseCode == BillingClient.BillingResponse.OK) {
            //здесь мы можем запросить информацию о товарах и покупках

        }
    }

    @Override
    public void onBillingServiceDisconnected() {
        //сюда мы попадем если что-то пойдет не так
    }
});

В метод onPurchasesUpdated() мы попадаем когда покупка осуществлена, в методе onBillingSetupFinished() можно запросить информацию о товарах и покупках.

Запросить информацию о товарах. Поместите querySkuDetails() в onBillingSetupFinished().


private Map<String, SkuDetails> mSkuDetailsMap = new HashMap<>();
private String mSkuId = "sku_id_1";
...
@Override
public void onBillingSetupFinished(@BillingClient.BillingResponse int billingResponseCode) {
    if (billingResponseCode == BillingClient.BillingResponse.OK) {
        //здесь мы можем запросить информацию о товарах и покупках
        querySkuDetails(); //запрос о товарах

    }
}
...
private void querySkuDetails() {
    SkuDetailsParams.Builder skuDetailsParamsBuilder = SkuDetailsParams.newBuilder();
    List<String> skuList = new ArrayList<>();
    skuList.add(mSkuId);
    skuDetailsParamsBuilder.setSkusList(skuList).setType(BillingClient.SkuType.INAPP);
    mBillingClient.querySkuDetailsAsync(skuDetailsParamsBuilder.build(), new SkuDetailsResponseListener() {
        @Override
        public void onSkuDetailsResponse(int responseCode, List<SkuDetails> skuDetailsList) {
            if (responseCode == 0) {
                for (SkuDetails skuDetails : skuDetailsList) {
                    mSkuDetailsMap.put(skuDetails.getSku(), skuDetails);
                }
            }
        }
    });
}

В коде вы могли заметить понятие SKU, что это? SKU — от английского Stock Keeping Unit (идентификатор товарной позиции).

Теперь в mSkuDetailsMap у нас лежит вся информация о товарах (имя, описание, цена), зарегистрированных в Play Console данного приложения (об этом позже). Обратите внимание на эту строку skuList.add(mSkuId);, здесь мы добавили id товара из Play Console, перечислите здесь все товары, с которыми вы хотите взаимодействовать. У нас товар один —sku_id_1.

Все готово к тому, чтобы выполнить запрос на покупку. Передаем id товара. Запустите этот метод, например, по клику на кнопку.

public void launchBilling(String skuId) {
    BillingFlowParams billingFlowParams = BillingFlowParams.newBuilder()
            .setSkuDetails(mSkuDetailsMap.get(skuId))
            .build();
    mBillingClient.launchBillingFlow(this, billingFlowParams);
}

Теперь, запустив этот метод, вы увидите вот такое диалоговое окно (прим. картинки из Интернета).

image

Теперь если пользователь купит товар — его ему надо предоставить. Добавьте метод payComplete() и осуществите в нем действия, предоставляющие доступ к купленному товару. Например, если пользователь покупал отключение рекламы, сделайте в этом методе так, чтобы реклама больше не показывалась.

...
@Override
public void onPurchasesUpdated(int responseCode, @Nullable List<Purchase> purchases) {
    if (responseCode == BillingClient.BillingResponse.OK && purchases != null) {
        //сюда мы попадем когда будет осуществлена покупка
        payComplete();
    }
}
...

Все хорошо, но если пользователь перезапустит приложение, наша программа ничего не знает о покупках. Надо запросить информацию о них. Сделайте это в onBillingSetupFinished().


@Override
public void onBillingSetupFinished(@BillingClient.BillingResponse int billingResponseCode) {
    if (billingResponseCode == BillingClient.BillingResponse.OK) {
        //здесь мы можем запросить информацию о товарах и покупках
        querySkuDetails(); //запрос о товарах
        List<Purchase> purchasesList = queryPurchases(); //запрос о покупках

        //если товар уже куплен, предоставить его пользователю
        for (int i = 0; i < purchasesList.size(); i++) {
            String purchaseId = purchasesList.get(i).getSku();
            if(TextUtils.equals(mSkuId, purchaseId)) {
                payComplete();
            }
        }
    }
}
...
private List<Purchase> queryPurchases() {
    Purchase.PurchasesResult purchasesResult = mBillingClient.queryPurchases(BillingClient.SkuType.INAPP);
    return purchasesResult.getPurchasesList();
}

В purchasesList попадает список всех покупок, сделанных пользователем.

Делаем проверку: если товар куплен — выполнить payComplete().

Готово. Осталось это приложение опубликовать в Play Console и добавить товары. Как добавить товар: Описание страницы приложения > Контент для продажи > Создать ограниченный контент.

Примечание 1: Вы не сможете добавить товар пока не загрузите билд приложения в Play Console.

Примечание 2: Чтобы увидеть диалоговое окно о покупке, вам надо загрузить билд в Play Console, добавить товар и подождать какое-то время (~30 минут — 1 час — 3 часа), пока товар обновится, только после этого появится диалоговое окно и можно будет осуществить покупку.

Примечание 3: Ошибка Please fix the input params. SKU can't be null — товар в Play Console еще не успел обновиться, подождите.

Примечание 4: Вы можете столкнуться с ошибкой Error «Your transaction cannot be completed», в логах как response code 6 пока будете тестировать. По каким причинам это происходит мне точно неизвестно, но по моим наблюдениям это происходит после частых манипуляций с покупкой и возвратом товара. Чтобы это починить перейдите в меню банковских карт и передобавьте вашу карту. Как этого избежать? Добавьте ваш аккаунт в Play Console в качестве тестировщика и покупайте только с тестовой карточки.

Демо на GitHub

Купите мне кофе

(Кстати, на Хабре работает система донейтов по кнопке под статьёй — прим. модератора).
+17
4.7k 92
Comments 23
Top of the day