SDKBOX IAP subscriptions

I have few questions about using SDKBOX IAP to work with subs type item on iOS.

I tired to parse the receiptCipheredPayload by PKCS7 or ANS1 string, both cannot get the correct decoded receipt, am I doing something wrong?

I was decoding the receipt to get the subs expiring date, is there a simply way to do the subs iap restore?

When first init of SDKBOX IAP, it will automatically call onRestored callback couple times with same transaction id, but when I manually call sdkbox::IAP::restore() it has no IAP record (new sandbox account), is this normal?

Thanks.

1 Like

receiptCipheredPayload is encode by base64

you should use the receipt to check if subs is valid

i tried, SDKBOX IAP will not automatically call restore when init. i think you had call restore.

Thank you for the reply.
This is the procedure of my test.

  1. Use an sandbox account to purchase IAP subs.
  2. Re launch app.

The log will first shows onInitialized callback then onSuccess with the subs product.

Game: onInitialized SDKBox IAP init success.
Game: onSuccess IAP vip-1 1000000123456789
Game: onSuccess IAP vip-1 1000000123456789
Game: onSuccess IAP vip-1 1000000123456789

It seems SDKBOX when initiating will load the local receipt and call onSuccess.

I found out after set sdkbox::IAP::enableUserSideVerification(true).
Then purchase whatever IAP item, relaunch the app will happens the above onSuccess problem.

those callback is trigger by ios IAP. sdkbox will call onSuccesss only get success event from ios IAP.

in sandbox, subscription duration times is shorter then actual duration.

I understand the sandbox duration time is much shorter than actual, but it is not related to this problem, if I turn off sdkbox::IAP::enableUserSideVerification(false) or just comment it to use default settings, it will be fine, it won’t call onSuccess after onInitialized with same testing procedures.
Also, is it correct to call multiple times onSuccess of the same transaction id? I use native code to check the AppStore receipt, it is not the correct transaction id at all.

do you check res/sdkbox_config.json?

have you remove other sample iap config added by sdkbox?

between, which sdkbox iap version you using?
i remember last time sdkbox iap will auto restore iap even for non-consumable after app start / restart / purchased iap.

i’m not sure since which version the issue gone, but it not happen on version v2.4.1.1 and v2.4.3.3

I’m using sdkbox 2.4.3.3, I have a temporary fix by my own implementation using native code which avoiding to use sdkbox::IAP::restore(), now everything work perfectly.

i check the code again, didn’t restore when iap init.

and can you share your fix?

I just changed the flow of purchase, onSuccess only process consumable items, non consumable item will call my restorePurchase implementation.

if (product.type == sdkbox::IAP_Type::CONSUMABLE) {
    if (product.name == IAP_POTION_HP) {
        // add item hp
        _consumableIap += 1;
        DataManager::getInstance()->saveData(KEY_IAP_POTION_HP, _consumableIap);
        _consumableIapLabel->setString(StringUtils::format("Consumable IAP\n%d", _consumableIap));
    }
} else {
    // Non consumable item use restore.
    Game::getInstance()->restoreProduct();
}

The restore function will proceed the receipt verification and then call my onRestored implementation.

if let expireDate = iapItem.subscriptionExpirationDate {
    // The IAP item is subscription.
    let currentDate = Date()
    if currentDate < expireDate {
        let formatter = DateFormatter()
        formatter.dateFormat = "yyyy'-'MM'-'dd HH':'mm':'ss"
        formatter.timeZone = TimeZone.current
        let dateString = formatter.string(from: expireDate)
        PurchaseValidatorWrapper.sharedInstance().onRestored(iapItem.productIdentifier, expireDate: dateString)
    }
} else {
    // The IAP item is non consumable.
    PurchaseValidatorWrapper.sharedInstance().onRestored(iapItem.productIdentifier, expireDate: "")
}

At the end, due to the recent purchase will show in the receipt no matter what iap type, so the onRestore callback need to check the restored item type, skip it if it is consumable.