React-native-iap: рд╕рд░реНрд╡рд░ рд╕рд╛рдЗрдб рд╕реЗ рдЖрдИрдУрдПрд╕ рд░рд╕реАрдж рд╕рддреНрдпрд╛рдкрди

рдХреЛ рдирд┐рд░реНрдорд┐рдд 28 рдЬрдире░ 2020  ┬╖  9рдЯрд┐рдкреНрдкрдгрд┐рдпрд╛рдБ  ┬╖  рд╕реНрд░реЛрдд: dooboolab/react-native-iap

рдореИрдВ рдЖрдИрдУрдПрд╕ рд░рд╕реАрдж рдХреЛ рд╕рддреНрдпрд╛рдкрд┐рдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдЕрдкрдиреЗ рдмреИрдХрдПрдВрдб рд╕рд░реНрд╡рд░ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░ рд░рд╣рд╛ рд╣реВрдВред рдЙрд╕рдХреЗ рд▓рд┐рдП рдореИрдВрдиреЗ рдЬреЛ рдХреБрдЫ рдХрд┐рдпрд╛ рд╣реИ рд╡рд╣ рдПрдХ рдкреЛрд╕реНрдЯ рдЕрдиреБрд░реЛрдз рдореЗрдВ рдПрдкреНрд▓рд┐рдХреЗрд╢рди рд╕рд░реНрд╡рд░ рдХреЛ рдЦрд░реАрджред рд▓реЗрдирджреЗрди рд░рд╕реАрдж рдкрд╛рд╕ рдХрд░ рджрд┐рдпрд╛ рд╣реИред рдореИрдВ рдЬрд╛рдирдирд╛ рдЪрд╛рд╣рддрд╛ рд╣реВрдВ рдХрд┐ рдХреНрдпрд╛ рдЦрд░реАрджред рд▓реЗрдирджреЗрди рд░рд╕реАрдж рдмреЗрд╕ 64 рдПрдиреНрдХреЛрдбреЗрдб рд░рд╕реАрдж рдбреЗрдЯрд╛ рджреЗрддрд╛ рд╣реИ рдпрд╛ рдХреНрдпрд╛? рдореБрдЭреЗ рддреНрд░реБрдЯрд┐ рдорд┐рд▓ рд░рд╣реА рд╣реИ: 21002 рд╡рд░реНрддрдорд╛рди рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди рдХреЗ рд╕рд╛рде

requestServerForReceiptVerification = (purchase: InAppPurchase | SubscriptionPurchase) => {
        const receipt = purchase.transactionReceipt;
        if (receipt) {
            // Hit Server API for Receipt Validation
            if (Platform.OS == 'ios') {
                let headers = {
                    'Content-Type': 'application/json'
                }
                Stores.UserStore.hitVerifyiOSReceiptAPI(receipt, headers, this.dropdown, (response: any) => {
                    finishTransaction(purchase).then(() => {
                        console.warn('Trasaction Finished');
                    }).catch((error) => {
                        console.warn(error.message);
                    })
                })
            } 
        }
    }
ЁЯУ▒ iOS ЁЯХ╡я╕ПтАНтЩВя╕П need more investigation ЁЯЪ╢ЁЯП╗ stale

рд╕рдмрд╕реЗ рдЙрдкрдпреЛрдЧреА рдЯрд┐рдкреНрдкрдгреА

рдЗрд╕реЗ рдЬрд╛рдБрдЪреЗрдВ

const IOS_SHARED_PWD = "********";

async function validateIOS() {
    const latestPurchase = await getLatestPurchase();
    if (latestPurchase) {
        return false;
    }

    return RNIap.validateReceiptIos(
        {
            "receipt-data": latestPurchase.transactionReceipt,
            "password": IOS_SHARED_PWD,
            "exclude-old-transactions": false
        },
        false
    )
        .then(uncheckedValidation => {
            //check test receipt
            if (uncheckedValidation?.status === 21007) {
                return RNIap.validateReceiptIos(
                    {
                        "receipt-data": latestPurchase.transactionReceipt,
                        "password": IOS_SHARED_PWD,
                        "exclude-old-transactions": false
                    },
                    true
                );
            } else {
                return uncheckedValidation;
            }
        })
        .then(checkedValidation => {
            return isValidReceipt(checkedValidation);
        });
}

function getLatestPurchase() {
    return RNIap.getAvailablePurchases().then(purchases => {
        return purchases?.sort((a, b) => Number(b.transactionDate) - Number(a.transactionDate))?.[0] || null;
    });
}

function isValidReceipt(checkedValidation) {
    if (!checkedValidation) {
        return false;
    }

    // check is valid validation request
    if (checkedValidation.status === 21006 || checkedValidation.status === 21010) {
        return false;
    }

    const { latest_receipt_info: latestReceiptInfo } = checkedValidation;
    const latestReceipt = latestReceiptInfo
        ?.sort((a, b) => Number(b.purchase_date_ms) - Number(a.purchase_date_ms))
        ?.find(receipt => receipt.product_id === "some.product.id")?.[0];

    // no receipt
    if (!latestReceipt) {
        return false;
    }

    // refunded receipt
    if (latestReceipt.cancellation_date) {
        return false;
    }

    // expired receipt
    if (Number(latestReceipt.expires_date_ms) < Date.now()) {
        return false;
    }

    return checkedValidation.status === 0;
}

рд╕рднреА 9 рдЯрд┐рдкреНрдкрдгрд┐рдпрд╛рдБ

@hyochan рдХреНрдпрд╛ рдЖрдк рдХреГрдкрдпрд╛ рдпрд╣рд╛рдБ рдорджрдж рдХрд░ рд╕рдХрддреЗ рд╣реИрдВред рд▓реЗрдирджреЗрди рд░рд╕реАрдж рдЬреЛ рдореБрдЭреЗ рдорд┐рд▓ рд░рд╣реА рд╣реИ.. рдХреНрдпрд╛ рдпрд╣ рдЖрдзрд╛рд░ 64 рдПрдиреНрдХреЛрдбреЗрдб рд╕реНрдЯреНрд░рд┐рдВрдЧ рд╣реИ? рдпрджрд┐ рдирд╣реАрдВ рддреЛ рдореИрдВ рдЗрд╕реЗ рдХреИрд╕реЗ рдкрд░рд┐рд╡рд░реНрддрд┐рдд рдХрд░ рд╕рдХрддрд╛ рд╣реВрдВред рдореИрдВ рдЗрд╕реЗ рдЕрдкрдиреЗ рдмреАрдИ рд╕рд░реНрд╡рд░ рдкрд░ рднреЗрдЬ рд░рд╣рд╛ рд╣реВрдВ рдЬрд╣рд╛рдВ рд╕реЗ рдореИрдВ рд╕реЗрдм рд░рд╕реАрдж рд╕рддреНрдпрд╛рдкрди рдПрдкреАрдЖрдИ рдорд╛рд░ рд░рд╣рд╛ рд╣реВрдВред

рдореИрдВ рдЕрднреА рдЗрд╕реА рдореБрджреНрджреЗ рдХреЛ рджреЗрдЦ рд░рд╣рд╛ рд╣реВрдВред рдЖрдИрдУрдПрд╕ рдкрд░ рд▓реЗрдирджреЗрди рд░рд╕реАрдж рдмреЗрд╕ 64 рд╕реНрдЯреНрд░рд┐рдВрдЧ рдХреА рддрд░рд╣ "рджрд┐рдЦрддрд╛ рд╣реИ", рд▓реЗрдХрд┐рди рдРрд╕рд╛ рдирд╣реАрдВ рд╣реИред рдЕрдЧрд░ рдореИрдВ рдЗрд╕реЗ рдбрд┐рд╡рд╛рдЗрд╕ рдкрд░ рдбреАрдХреЛрдб рдХрд░рддрд╛ рд╣реВрдВ рдФрд░ рдХрдВрд╕реЛрд▓ рдореЗрдВ рдЖрдЙрдЯрдкреБрдЯ рдХрд░рддрд╛ рд╣реВрдВ, рддреЛ рдореБрдЭреЗ рдХрднреА-рдХрднреА рдпрд╛рджреГрдЪреНрдЫрд┐рдХ рд╢рдмреНрджреЛрдВ рдХреЗ рд╕рд╛рде рдХрдЪрд░реЗ рдХреА рд╕реНрдХреНрд░реАрди рдорд┐рд▓рддреА рд╣реИред

рдлрд┐рд░ рдореИрдВрдиреЗ рдЗрд╕реЗ рднреЗрдЬрдиреЗ рдХрд╛ рдкреНрд░рдпрд╛рд╕ рдХрд┐рдпрд╛, рдЬреИрд╕рд╛ рдХрд┐ рдореЗрд░реЗ рдмреАрдИ рд╕рд░реНрд╡рд░ рдкрд░ рдирд┐рд░реНрднрд░ рд╣реИред рд╡рд╣рд╛рдВ, рдореИрдВрдиреЗ рдЗрд╕ рдХреЛрдб рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рдбреЙрдЯрдиреЗрдЯ рдХреЛрд░ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рдЗрд╕реЗ рдбреАрдХреЛрдб рдХрд┐рдпрд╛:

string base64Decoded;
byte[] data = System.Convert.FromBase64String(receiptString);
base64Decoded = System.Text.Encoding.ASCII.GetString(data);
Console.WriteLine("ios receiptString:");
Console.WriteLine(base64Decoded);

рдЙрд╕рдХреЗ рд▓рд┐рдП рдЖрдЙрдЯрдкреБрдЯ рд╣реИ:
Screen Shot 2020-02-07 at 10 58 37 AM

рдореЗрд░рд╛ рд╡рд┐рдЪрд╛рд░ рд╣реИ рдХрд┐ рд░рд╕реАрдж рдореЗрдВ рдкреНрд░рддреНрдпреЗрдХ рдкреНрд░рд╡рд┐рд╖реНрдЯрд┐ рдПрдиреНрдХреЛрдбреЗрдб рдереА ... рдлрд┐рд░ рдкреВрд░реА рд░рд╕реАрдж рдПрдиреНрдХреЛрдбреЗрдб рдереАред рдореИрдВ рдЙрд╕ рд╕рд┐рджреНрдзрд╛рдВрдд рдХрд╛ рдкрд░реАрдХреНрд╖рдг рд╢реБрд░реВ рдХрд░рдиреЗ рд╕реЗ рдкрд╣рд▓реЗ рдпрд╣рд╛рдВ рдПрдХ рдЙрддреНрддрд░ рдЦреЛрдЬрдиреЗ рдХреА рдЙрдореНрдореАрдж рдХрд░ рд░рд╣рд╛ рдерд╛ ... рд▓реЗрдХрд┐рди рдореИрдВ рдЖрдЧреЗ рдЬрд╛рдХрд░ рдРрд╕рд╛ рдХрд░рдиреЗ рдЬрд╛ рд░рд╣рд╛ рд╣реВрдВред

рдореИрдВрдиреЗ рдереЛрдбрд╝реА рдкреНрд░рдЧрддрд┐ рдХреА рд╣реИред рдореИрдВ рдбрд┐рдХреЛрдб рдХреА рдЬрд╛ рд╕рдХрдиреЗ рд╡рд╛рд▓реА рдХрд┐рд╕реА рднреА рдЪреАрдЬрд╝ рдХреЛ рд╡рд╛рдкрд╕ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдПValidReceiptIos рдлрд╝рдВрдХреНрд╢рди рдкреНрд░рд╛рдкреНрдд рдХрд░рдиреЗ рдореЗрдВ рд╕рдХреНрд╖рдо рдирд╣реАрдВ рдерд╛ред рдЙрд╕ рдкрд░ рдореЗрд░рд╛ рд╡рд┐рдЪрд╛рд░ рдпрд╣ рд╣реИ рдХрд┐ рдРрдкреНрдкрд▓ рдиреЗ рдЗрд╕реЗ рдПрдиреНрдХреЛрдб рдХрд░рдиреЗ рдХреЗ рддрд░реАрдХреЗ рдореЗрдВ рдмрджрд▓рд╛рд╡ рдХрд┐рдпрд╛ рд╣реИред

рдореИрдВ рдХрдЪреНрдЪреЗ рд╕реНрдЯреНрд░рд┐рдВрдЧ рдХреЛ рдЕрдкрдиреЗ рд╕рд░реНрд╡рд░ рддрдХ рдкрд╛рд╕ рдХрд░рдХреЗ рдФрд░ рдлрд┐рд░ рдЗрд╕реЗ VerifyReceipt рдПрдВрдбрдкреЙрдЗрдВрдЯ рдкрд░ рдкреЛрд╕реНрдЯ рдХрд░рдХреЗ рдкреНрд░рдпреЛрдЧ рдХрд░рдиреЗ рдпреЛрдЧреНрдп рдЬрд╛рдирдХрд╛рд░реА рдкреНрд░рд╛рдкреНрдд рдХрд░рдиреЗ рдореЗрдВ рд╕рдХреНрд╖рдо рдерд╛ред рдореИрдВрдиреЗ рдЗрд╕реЗ рдПрдХ рдЧрд╛рдЗрдб рдХреЗ рд░реВрдк рдореЗрдВ рдЗрд╕реНрддреЗрдорд╛рд▓ рдХрд┐рдпрд╛: https://developer.apple.com/library/archive/releasenotes/General/ValidateAppStoreReceipt/Chapters/ValidateRemotely.html

@рд▓реАрд▓реИрдВрдбрдХреНрд▓реЗ :
"рдореИрдВ рдЕрдкрдиреЗ рд╕рд░реНрд╡рд░ рддрдХ рдХрдЪреНрдЪреЗ рд╕реНрдЯреНрд░рд┐рдВрдЧ рдХреЛ рдкрд╛рд╕ рдХрд░рдХреЗ рдФрд░ рдлрд┐рд░ рдЗрд╕реЗ рд╕рддреНрдпрд╛рдкрд┐рдд рд░рд╕реАрдж рд╕рдорд╛рдкрди рдмрд┐рдВрджреБ рдкрд░ рдкреЛрд╕реНрдЯ рдХрд░рдХреЗ рдкреНрд░рдпреЛрдЧ рдХрд░рдиреЗ рдпреЛрдЧреНрдп рдЬрд╛рдирдХрд╛рд░реА рдкреНрд░рд╛рдкреНрдд рдХрд░рдиреЗ рдореЗрдВ рд╕рдХреНрд╖рдо рдерд╛ред"
рдХреНрдпрд╛ рдЖрдкрдиреЗ рдЕрднреА рдЙрд╕ рд▓реЗрдирджреЗрди рд░рд╕реАрдж рд╕реНрдЯреНрд░рд┐рдВрдЧ рдХреЛ рдмреАрдИ рдкрд░ рднреЗрдЬрд╛ рд╣реИ?
рдореИрдВ рдРрдкреНрдкрд▓ рджрд╕реНрддрд╛рд╡реЗрдЬрд╝реАрдХрд░рдг рдХреЗ рдорд╛рдзреНрдпрдо рд╕реЗ рдЪрд▓рд╛ рдЧрдпрд╛ рд╣реВрдВ рд▓реЗрдХрд┐рди рд░рд╕реАрдж рдбреЗрдЯрд╛ рдмрдирд╛рдиреЗ рдХреА рд╡рд┐рдзрд┐ рджреЗрд╢реА рдЖрдИрдУрдПрд╕ рдПрдкреНрд▓рд┐рдХреЗрд╢рди рдХреЗ рд▓рд┐рдП рд╣реИ рдЬрд┐рд╕рдореЗрдВ рд╣рдореЗрдВ рдРрдкрд╕реНрдЯреЛрд░ рд░рд╕реАрдж рдпреВрдЖрд░рдПрд▓ рдорд┐рд▓рддрд╛ рд╣реИред

рд╣рд╛рдВред рдЖрдИрдПрдкреА рд╕реЗ рдкреНрд░рд╛рдкреНрдд рдСрдмреНрдЬреЗрдХреНрдЯ рдХреЛ рд╕рд░реНрд╡рд░ рдкрд░ рдкрд╛рд╕ рдХрд░реЗрдВ, рдлрд┐рд░ рдЗрд╕реЗ рд╡реЗрдмрд╕рд╛рдЗрдЯ рдкрд░ рднреЗрдЬреЗрдВ рдФрд░ рдЖрдкрдХреЛ рдПрдХ JSON рдСрдмреНрдЬреЗрдХреНрдЯ рд╡рд╛рдкрд╕ рдорд┐рд▓ рдЬрд╛рдПред

рдареАрдХ рд╣реИ... рдореИрдВ рдЕрднреА рдпрд╣реАрдВ рд╣реВрдБ....

рдпрд╣ рд╡рд╣ рдХреЛрдб рд╣реИ рдЬреЛ рдореЗрд░реЗ рдкрд╛рд╕ рдореЗрд░реЗ рдРрдк рдореЗрдВ рд╣реИ:

this.purchaseUpdateSubscription = purchaseUpdatedListener(
  (purchase: InAppPurchase | SubscriptionPurchase) => {
    console.log('purchaseUpdateSubscription called');
    if (purchase) {
      try {
        sendTransactionReceipt(this.state.profile.userId, purchase.transactionReceipt, this.state.token)
          .then(transactionReceipt => {
            finishTransaction(purchase, false)
              .then(finish => {
                this.setState({ transactionReceipt }, () => { this.sendingTransactionReceipt = false; });
              })
              .catch(err => {
                console.log('FinishTransaction ERROR: ' + err);
                this.sendingTransactionReceipt = false;
              });
          })
          .catch(() => {
            this.sendingTransactionReceipt = false;
          });
      } catch (ackErr) {
        console.warn('ackErr', ackErr);
      }
    }
  },
);

рдмреАрдИ рд╕рд░реНрд╡рд░ рдкрд░, рдореИрдВ рдмрд╕ рдирд┐рдореНрдирд▓рд┐рдЦрд┐рдд рдСрдмреНрдЬреЗрдХреНрдЯ рдмрдирд╛рддрд╛ рд╣реВрдВ рдФрд░ рдЗрд╕реЗ /verifyReceipt рдПрдВрдбрдкреЙрдЗрдВрдЯ рдкрд░ рдкреЛрд╕реНрдЯ рдХрд░рддрд╛ рд╣реВрдВ (рдЙрдкрд░реЛрдХреНрдд рджрд╕реНрддрд╛рд╡реЗрдЬ рдореЗрдВ рд╕рд░реНрд╡рд░ рд╕реНрдерд╛рдиреЛрдВ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ)ред

{
  "receipt-data": <purchase.transactionReceipt received from app>,
  "password": <secret password from within your apple account>,
  "exclude-old-transactions": true
}

рдореИрдВ рдорд╛рдиреНрдп рдЬрд╛рдирдХрд╛рд░реА рдХреЗ рд╕рд╛рде рдкреНрд░рддрд┐рдХреНрд░рд┐рдпрд╛рдПрдБ рд╡рд╛рдкрд╕ рдкреНрд░рд╛рдкреНрдд рдХрд░рдиреЗ рдореЗрдВ рд╕рдХреНрд╖рдо рд╣реВрдБред рдкреНрд░рддрд┐рдХреНрд░рд┐рдпрд╛ рдХрд╛ рдПрдХ рд╣рд┐рд╕реНрд╕рд╛ "рдирд╡реАрдирддрдо_рд░рд╕реАрдж" рдкреНрд░рд╡рд┐рд╖реНрдЯрд┐ рд╣реИ (рдмрд╛рдж рдореЗрдВ рдЙрдкрдпреЛрдЧ рдХрд┐рдпрд╛ рдЧрдпрд╛)ред рдореИрдВ рдЕрдкрдиреЗ рдбреЗрдЯрд╛рдмреЗрд╕ рдореЗрдВ рд╕рдм рдХреБрдЫ рд╕реНрдЯреЛрд░ рдХрд░рддрд╛ рд╣реВрдВ рдФрд░ рд╕рд╛рде рд╣реА рдЬрд╛рдирдХрд╛рд░реА рдХреЛ рдРрдк рдкрд░ рд╡рд╛рдкрд╕ рднреЗрдЬ рджреЗрддрд╛ рд╣реВрдВ рддрд╛рдХрд┐ рд╡рд╣ рдлрд┐рдирд┐рд╢ рдЯреНрд░рд╛рдВрдЬрд╝реЗрдХреНрд╢рди рдХреЛ рдХреЙрд▓ рдХрд░ рд╕рдХреЗ рдФрд░ рд╡реИрдз рд░рд╕реАрдж рдХреЛ рд░рд╛рдЬреНрдп рдореЗрдВ рдЗрд╕реНрддреЗрдорд╛рд▓ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рд╕реНрдЯреЛрд░ рдХрд░ рд╕рдХреЗред

рдореИрдВ рдПрдХ рдХреНрд░реЙрди рдЬреЙрдм рдкрд░ рднреА рдХрд╛рдо рдХрд░ рд░рд╣рд╛ рд╣реВрдВ рдЬреЛ рджрд┐рди рдореЗрдВ рдПрдХ рдмрд╛рд░ рдЙрди рд╕рднреА рд╕рдмреНрд╕рдХреНрд░рд┐рдкреНрд╢рди рдХреЛ рдкрдХрдбрд╝рдиреЗ рдХреЗ рд▓рд┐рдП рдирд┐рд╖реНрдкрд╛рджрд┐рдд рдХрд░реЗрдЧрд╛ рдЬреЛ рд╕рдХреНрд░рд┐рдп рдХреЗ рд░реВрдк рдореЗрдВ рджрд┐рдЦ рд░рд╣реЗ рд╣реИрдВ рдФрд░ рд╕рдорд╛рдкреНрддрд┐ рддрд┐рдерд┐ рдкрд╛рд░рд┐рдд рдХрд░ рдЪреБрдХреЗ рд╣реИрдВред рдпрд╣ рдЙрд╕реА рдкреНрд░рдХреНрд░рд┐рдпрд╛ рдХрд╛ рдЕрдиреБрд╕рд░рдг рдХрд░рддрд╛ рд╣реИ рдЬрд╣рд╛рдБ рддрдХ рд╡реЗрд░реАрдлрд┐рдХреЗрд╢рди рдХреЛ рд╕реВрдЪрдирд╛ рднреЗрдЬрдиреЗ рдХреА рдкреНрд░рдХреНрд░рд┐рдпрд╛ рд╣реЛрддреА рд╣реИред "рд░рд╕реАрдж-рдбреЗрдЯрд╛" рдЬреЛ рдореИрдВ рдкрд╛рд╕ рдХрд░рддрд╛ рд╣реВрдВ рд╡рд╣ "рдирд╡реАрдирддрдо_рд░рд╕реАрдж" рд╣реИ рдЬрд┐рд╕реЗ рдореИрдВрдиреЗ рдкрд┐рдЫрд▓реЗ рд╕рддреНрдпрд╛рдкрди рд░рд╕реАрдж рдХреЙрд▓ рд╕реЗ рд╕рдВрдЧреНрд░рд╣реАрдд рдХрд┐рдпрд╛ рдерд╛ред

рдЬрд╛рд╣рд┐рд░ рд╣реИ, рдХреБрдЫ рдЕрдЬреАрдм рддрд░реАрдХрд╛ рд╣реИ рдХрд┐ рд╕реИрдВрдбрдмреЙрдХреНрд╕ рдСрдЯреЛ-рдирд╡реАрдиреАрдХрд░рдг рд╕рджрд╕реНрдпрддрд╛ рдХреЛ рд╕рдВрднрд╛рд▓рддрд╛ рд╣реИ, рдЗрд╕рд▓рд┐рдП рдореИрдВ рдРрдкреНрдкрд▓ рдбреЗрд╡рд▓рдкрд░ рдлрд╝реЛрд░рдо рдкрд░ рдкреНрд░рддрд┐рдХреНрд░рд┐рдпрд╛ рдкреНрд░рд╛рдкреНрдд рдХрд░рдиреЗ рдХреА рдкреНрд░рддреАрдХреНрд╖рд╛ рдХрд░ рд░рд╣рд╛ рд╣реВрдВ рдХрд┐ рдореБрдЭреЗ рд╡рд╛рд╕реНрддрд╡ рдореЗрдВ рдХреНрдпрд╛ рджреЗрдЦрдирд╛ рдЪрд╛рд╣рд┐рдПред

рдЬреЛ рд╕реНрдерд┐рддрд┐ рдореИрдВ рджреЗрдЦ рд░рд╣рд╛ рд╣реВрдВ рд╡рд╣ рдпрд╣ рд╣реИ рдХрд┐ рд╕рджрд╕реНрдпрддрд╛ рдЦрд░реАрджрдиреЗ рдХреЗ рдмрд╛рдж, рдореБрдЭреЗ рдПрдХ рдкреНрд░рддрд┐рдХреНрд░рд┐рдпрд╛ рдорд┐рд▓рддреА рд╣реИ рдЬреЛ рд╕реНрд╡рддрдГ рдирд╡реАрдиреАрдХрд░рдг рдХреЛ рд╕рддреНрдп рдХреЗ рд░реВрдк рдореЗрдВ рджрд┐рдЦрд╛рддреА рд╣реИ (рд▓рдВрдмрд┐рдд_рдирд╡реАрдиреАрдХрд░рдг_рдЗрдиреНрдлреЛ [0]ред рд╕рддреНрдпрд╛рдкрди рд░рд╕реАрдж рд╕реЗ auto_renew_status 1 рдХреЗ рд░реВрдк рдореЗрдВ рджрд┐рдЦрд╛рддрд╛ рд╣реИ) рдФрд░ рд╕рдорд╛рдкреНрддрд┐_рдбреЗрдЯ рдкреНрд░рд╡рд┐рд╖реНрдЯрд┐рдпрд╛рдВ (рд╡рд╣рд╛рдВ 3 рд╣реИ) рджрд┐рдЦрд╛рддреА рд╣реИ рдХрд┐ рдпрд╣ рдореЗрдВ рд╣реИ рднрд╡рд┐рд╖реНрдп (5 рдорд┐рдирдЯ)ред рдпрджрд┐ рдореИрдВ рд╕рдордп рд╕рдорд╛рдкреНрдд рд╣реЛрдиреЗ рдХреЗ рдмрд╛рдж рддрдХ рдкреНрд░рддреАрдХреНрд╖рд╛ рдХрд░рддрд╛ рд╣реВрдВ рдФрд░ рдлрд┐рд░ рд╕реЗ рд╕рддреНрдпрд╛рдкрд┐рдд рд░рд╕реАрдж рдХреЛ рдХреЙрд▓ рдХрд░рддрд╛ рд╣реВрдВ, рддреЛ рдпрд╣ рд╕рдорд╛рдкреНрддрд┐_рдбреЗрдЯ рдФрд░ рдСрдЯреЛ рдирд╡реАрдиреАрдХрд░рдг рдХреЗ рд▓рд┐рдП рд╕рдорд╛рди рдорд╛рди рджрд┐рдЦрд╛рдПрдЧрд╛ред

рдореЗрд░реА рдпреЛрдЬрдирд╛ рдСрдЯреЛ рдирд╡реАрдиреАрдХрд░рдг рдХреА рд╕реНрдерд┐рддрд┐ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдирд╛ рдерд╛ === рдЭреВрдареА рдФрд░ рд╕рдорд╛рдкреНрддрд┐ рд╕рдордп <рд╡рд░реНрддрдорд╛рди рд╕рдордп рдпрд╣ рдирд┐рд░реНрдзрд╛рд░рд┐рдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдХрд┐ рд╕рджрд╕реНрдпрддрд╛ рдХреЛ рдирд┐рд╖реНрдХреНрд░рд┐рдп рдХрд░рдирд╛ рд╣реИ рдпрд╛ рдирд╣реАрдВред рдХреНрдпрд╛ рдХрд┐рд╕реА рдФрд░ рдиреЗ рдЗрд╕ рдкреНрд░рддрд┐рдХреНрд░рд┐рдпрд╛ рдХреЛ VerifyReceipt рд╕реЗ рджреЗрдЦрд╛ рд╣реИ ????

рдЗрд╕реЗ рдЬрд╛рдБрдЪреЗрдВ

const IOS_SHARED_PWD = "********";

async function validateIOS() {
    const latestPurchase = await getLatestPurchase();
    if (latestPurchase) {
        return false;
    }

    return RNIap.validateReceiptIos(
        {
            "receipt-data": latestPurchase.transactionReceipt,
            "password": IOS_SHARED_PWD,
            "exclude-old-transactions": false
        },
        false
    )
        .then(uncheckedValidation => {
            //check test receipt
            if (uncheckedValidation?.status === 21007) {
                return RNIap.validateReceiptIos(
                    {
                        "receipt-data": latestPurchase.transactionReceipt,
                        "password": IOS_SHARED_PWD,
                        "exclude-old-transactions": false
                    },
                    true
                );
            } else {
                return uncheckedValidation;
            }
        })
        .then(checkedValidation => {
            return isValidReceipt(checkedValidation);
        });
}

function getLatestPurchase() {
    return RNIap.getAvailablePurchases().then(purchases => {
        return purchases?.sort((a, b) => Number(b.transactionDate) - Number(a.transactionDate))?.[0] || null;
    });
}

function isValidReceipt(checkedValidation) {
    if (!checkedValidation) {
        return false;
    }

    // check is valid validation request
    if (checkedValidation.status === 21006 || checkedValidation.status === 21010) {
        return false;
    }

    const { latest_receipt_info: latestReceiptInfo } = checkedValidation;
    const latestReceipt = latestReceiptInfo
        ?.sort((a, b) => Number(b.purchase_date_ms) - Number(a.purchase_date_ms))
        ?.find(receipt => receipt.product_id === "some.product.id")?.[0];

    // no receipt
    if (!latestReceipt) {
        return false;
    }

    // refunded receipt
    if (latestReceipt.cancellation_date) {
        return false;
    }

    // expired receipt
    if (Number(latestReceipt.expires_date_ms) < Date.now()) {
        return false;
    }

    return checkedValidation.status === 0;
}

рдЕрд░реЗ, рдРрд╕рд╛ рд▓рдЧрддрд╛ рд╣реИ рдХрд┐ рд╣рд╛рд▓ рд╣реА рдореЗрдВ рдЗрд╕ рдореБрджреНрджреЗ рдкрд░ рдХреЛрдИ рдЧрддрд┐рд╡рд┐рдзрд┐ рдирд╣реАрдВ рд╣реБрдИ рд╣реИред рдХреНрдпрд╛ рд╕рдорд╕реНрдпрд╛ рдХрд╛ рд╕рдорд╛рдзрд╛рди рдХрд░ рджрд┐рдпрд╛ рдЧрдпрд╛ рд╣реИ, рдпрд╛ рдХреНрдпрд╛ рдЗрд╕ рдкрд░ рдЕрднреА рднреА рд╕рдореБрджрд╛рдп рдХреЗ рдзреНрдпрд╛рди рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИ? рдпрджрд┐ рдЖрдЧреЗ рдХреЛрдИ рдЧрддрд┐рд╡рд┐рдзрд┐ рдирд╣реАрдВ рд╣реЛрддреА рд╣реИ, рддреЛ рдпрд╣ рд╕рдорд╕реНрдпрд╛ рдмрдВрдж рд╣реЛ рд╕рдХрддреА рд╣реИред рдЖрдк рдЗрд╕ рдореБрджреНрджреЗ рдХреЛ "рдЪрд░реНрдЪрд╛ рдХреЗ рд▓рд┐рдП" рдпрд╛ "рдЕрдЪреНрдЫрд╛ рдкрд╣рд▓рд╛ рдЕрдВрдХ" рдХреЗ рд░реВрдк рдореЗрдВ рднреА рд▓реЗрдмрд▓ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ рдФрд░ рдореИрдВ рдЗрд╕реЗ рдЦреБрд▓рд╛ рдЫреЛрдбрд╝ рджреВрдВрдЧрд╛ред рдЖрдкрдХреЗ рдпреЛрдЧрджрд╛рдиреЛрдВ рдХреЗ рд▓рд┐рдП рдзрдиреНрдпрд╡рд╛рджред

@leelandclay рдЕрдкрдирд╛ рд╕рдорд╛рдзрд╛рди рдбрд╛рд▓рдиреЗ рдХреЗ рд▓рд┐рдП рдзрдиреНрдпрд╡рд╛рджред рдЗрд╕рд╕реЗ рд╡рд╛рд╕реНрддрд╡ рдореЗрдВ рдмрд╣реБрдд рдорджрдж рдорд┐рд▓реА рдФрд░ рд╣рдо рдЕрдВрддрддрдГ рдЕрдкрдиреА рд░рд╕реАрдж рдХреЛ рд╕рддреНрдпрд╛рдкрд┐рдд рдХрд░рдиреЗ рдореЗрдВ рд╕рдХреНрд╖рдо рд╣реБрдПред рдзрдиреНрдпрд╡рд╛рдж !!

рдХреНрдпрд╛ рдпрд╣ рдкреГрд╖реНрда рдЙрдкрдпреЛрдЧреА рдерд╛?
0 / 5 - 0 рд░реЗрдЯрд┐рдВрдЧреНрд╕

рд╕рдВрдмрдВрдзрд┐рдд рдореБрджреНрджреЛрдВ

chetstone picture chetstone  ┬╖  4рдЯрд┐рдкреНрдкрдгрд┐рдпрд╛рдБ

HamzaIkram2727 picture HamzaIkram2727  ┬╖  3рдЯрд┐рдкреНрдкрдгрд┐рдпрд╛рдБ

iutin picture iutin  ┬╖  4рдЯрд┐рдкреНрдкрдгрд┐рдпрд╛рдБ

Gribadze picture Gribadze  ┬╖  4рдЯрд┐рдкреНрдкрдгрд┐рдпрд╛рдБ

jvandenaardweg picture jvandenaardweg  ┬╖  4рдЯрд┐рдкреНрдкрдгрд┐рдпрд╛рдБ