И как это до сих пор на Хабре нет статьи об этом? Не дело, надо исправлять.
Есть 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);
}
Теперь, запустив этот метод, вы увидите вот такое диалоговое окно (прим. картинки из Интернета).
Теперь если пользователь купит товар — его ему надо предоставить. Добавьте метод 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 в качестве тестировщика и покупайте только с тестовой карточки.
(Кстати, на Хабре работает система донейтов по кнопке под статьёй — прим. модератора).
Автор: habrahabrovec