I'm working on a new android project and I want to add in-app purchases to my app. When I add the codes, the purchases are returned to the user after 72 hours. I guess I'm skipping something.
Here's my code
public class InAppActivity extends AppCompatActivity implements PurchasesUpdatedListener {
private Button coinPack1;
private Button coinPack2;
private Button coinPack3;
private Button coinPack4;
private BillingClient billingClient;
private List<SkuDetails> inAPPDetailList = new ArrayList<>();
private List<SkuDetails> inAPPSubs = new ArrayList<>();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_in_app);
coinPack1 = (Button) findViewById(R.id.coinPack1);
coinPack2 = (Button) findViewById(R.id.coinPack2);
coinPack3 = (Button) findViewById(R.id.coinPack3);
coinPack4 = (Button) findViewById(R.id.coinPack4);
billingClient = BillingClient.newBuilder(this).enablePendingPurchases().setListener(this).build();
billingClient.startConnection(new BillingClientStateListener() {
@Override
public void onBillingSetupFinished(@NonNull BillingResult billingResult) {
if (billingResult.getResponseCode() == BillingClient.BillingResponseCode.OK){
checkState(true);
List<String> skuListInAPP = new ArrayList<>();
skuListInAPP.add("coin_pack");
skuListInAPP.add("coin_pack2");
skuListInAPP.add("coin_pack3");
skuListInAPP.add("coin_pack4");
SkuDetailsParams.Builder paramsInApp = SkuDetailsParams.newBuilder();
paramsInApp.setSkusList(skuListInAPP).setType(BillingClient.SkuType.INAPP);
billingClient.querySkuDetailsAsync(paramsInApp.build(), new SkuDetailsResponseListener() {
@Override
public void onSkuDetailsResponse(@NonNull BillingResult billingResult, @Nullable List<SkuDetails> list) {
inAPPDetailList = list;
}
});
List<String> skuListSubs = new ArrayList<>();
skuListSubs.add("ads_free");
SkuDetailsParams.Builder paramsSubs = SkuDetailsParams.newBuilder();
paramsSubs.setSkusList(skuListSubs);
paramsSubs.setSkusList(skuListSubs).setType(BillingClient.SkuType.SUBS);
billingClient.querySkuDetailsAsync(paramsSubs.build(), new SkuDetailsResponseListener() {
@Override
public void onSkuDetailsResponse(@NonNull BillingResult billingResult, @Nullable List<SkuDetails> list) {
inAPPSubs = list;
}
});
}else {
checkState(false);
Toast.makeText(InAppActivity.this, "Beklenmedik Bir Hata oluştu", Toast.LENGTH_SHORT).show();
}
}
@Override
public void onBillingServiceDisconnected() {
checkState(false);
Toast.makeText(InAppActivity.this, "Beklenmedik Bir Hata Oluştu", Toast.LENGTH_SHORT).show();
}
});
coinPack1.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
BillingFlowParams billingFlowParams = BillingFlowParams.newBuilder().setSkuDetails(inAPPDetailList.get(0)).build();
billingClient.launchBillingFlow(InAppActivity.this,billingFlowParams);
}
});
coinPack2.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
BillingFlowParams billingFlowParams = BillingFlowParams.newBuilder().setSkuDetails(inAPPDetailList.get(1)).build();
billingClient.launchBillingFlow(InAppActivity.this,billingFlowParams);
}
});
coinPack3.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
BillingFlowParams billingFlowParams = BillingFlowParams.newBuilder().setSkuDetails(inAPPDetailList.get(2)).build();
billingClient.launchBillingFlow(InAppActivity.this,billingFlowParams);
}
});
coinPack4.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
BillingFlowParams billingFlowParams = BillingFlowParams.newBuilder().setSkuDetails(inAPPDetailList.get(3)).build();
billingClient.launchBillingFlow(InAppActivity.this,billingFlowParams);
}
});
}
private void checkState(Boolean situation){
coinPack1.setEnabled(situation);
coinPack2.setEnabled(situation);
coinPack3.setEnabled(situation);
coinPack4.setEnabled(situation);
}
@Override
public void onPurchasesUpdated(@NonNull BillingResult billingResult, @Nullable List<Purchase> list) {
if (billingResult.getResponseCode() == BillingClient.BillingResponseCode.OK && list!= null){
for (Purchase purchase : list){
if(!purchase.isAcknowledged()){
AcknowledgePurchaseParams.newBuilder()
.setPurchaseToken(purchase.getPurchaseToken())
.build();
}
if (purchase.getSku().equals("coin_pack")){
Constant.TOTAL_COINS = Constant.TOTAL_COINS + 100;
Utils.UpdateCoin(getApplicationContext(), String.valueOf(Constant.TOTAL_COINS));
Toast.makeText(this, "Satın Alma Başarılı 100 Jeton. Destekleriniz için teşekkür ederiz", Toast.LENGTH_SHORT).show();
}
if (purchase.getSku().equals("coin_pack2")){
Constant.TOTAL_COINS = Constant.TOTAL_COINS + 200;
Utils.UpdateCoin(getApplicationContext(), String.valueOf(Constant.TOTAL_COINS));
Toast.makeText(this, "Satın Alma Başarılı 200 Jeton. Destekleriniz için teşekkür ederiz", Toast.LENGTH_SHORT).show();
}
if (purchase.getSku().equals("coin_pack3")){
Constant.TOTAL_COINS = Constant.TOTAL_COINS + 400;
Utils.UpdateCoin(getApplicationContext(), String.valueOf(Constant.TOTAL_COINS));
Toast.makeText(this, "Satın Alma Başarılı 400 Jeton. Destekleriniz için teşekkür ederiz", Toast.LENGTH_SHORT).show();
}
if (purchase.getSku().equals("coin_pack4")){
Constant.TOTAL_COINS = Constant.TOTAL_COINS + 600;
Utils.UpdateCoin(getApplicationContext(), String.valueOf(Constant.TOTAL_COINS));
Toast.makeText(this, "Satın Alma Başarılı 600 Jeton. Destekleriniz için teşekkür ederiz", Toast.LENGTH_SHORT).show();
}
}
}
if (billingResult.getResponseCode() == BillingClient.BillingResponseCode.USER_CANCELED){
Toast.makeText(getApplicationContext(), "Ödeme İptal Edildi!!!", Toast.LENGTH_SHORT).show();
}
}
Purchases work normally, when users purchase tokens are added to their accounts and some features can be used with these tokens. Tokens are added to users' accounts without any problem in test payments. However, when a real purchase is made, the payment is taken from the user and the fee is returned to the user after 72 hours. Thank you so much :)
You acknowledge part is incomplete, you are not calling billingClient.acknowledgePurchase() then the purchase is refunded :
you need something like this :