dooboolab-community / react-native-iap

In App Purchase module for React Native!
https://react-native-iap.dooboolab.com
MIT License
2.75k stars 632 forks source link

transactionReceipt is empty on iOS #2574

Open daimonkor opened 9 months ago

daimonkor commented 9 months ago

@baesumin Hello, I use setup({storekitMode: 'STOREKIT2_MODE'}); and I got "transactionReceipt":"" with help sandbox account and real device. Please help, version "12.10.8".

jsflor commented 9 months ago

@daimonkor Hi, in Storekit 2 the response isa signed JWT, you need to use Storekit 1 if you want to have a transactionReceipt

cervebar commented 9 months ago

In Storekit2 there is change to: verificationResultIOS (see here) aka jswRepresentation (code ).

WARN 1: also your backend need to be ready to handle this new way WARn 2: only supported in iOS 15+

dmk3141618 commented 7 months ago

So.. Don't we need any additional verification process right? It is already verified if it returns kind of this result? So now I just need to implement some App Store Server Notifications v2 logic on the server side?

In case of subscription, I can use App Store Server Notifications. But at the very first time, I need to use App Store server API. Because, suppose this situation, user clicks purchase subscription button and subscription purchased, and after that send this to my backend server. But App Store Server Notification noti will be arrived earlier than DB update. So When noti arrived, this logic can't find who purchased the subscription of this noti. So I need to call App Store Server API with transactionId and process it. After this, App Store Server Notifications will deal with this all.

If I need App Store Server API with transactionId, what is different with the verifyReceipt process of storekit1?

But a little bit weird. (in case of consumable product) It seems it is storekit2's new process. But I don't understand at some point. Do I just send this transactionId to my backend server and give this user an item? And even it's only a client side app, when it pass, then give them an item? How is it possible without backend verification? call some api like '/api/processPurchase' with transactionId, then just give them an item? Or just pass this requestPurchase, then it is verified then just give them an item?

checkCurrentPurchase... there is something to process { "productId": "myproduct1", "transactionId": "2000000123124", "transactionDate": 1700712123123, "transactionReceipt": "", "purchaseToken": "", "quantityIOS": 1, "originalTransactionDateIOS": 1700712123123, "originalTransactionIdentifierIOS": 2000000123124, "verificationResultIOS": xxx "appAccountToken": "" }

https://developer.apple.com/documentation/storekit/verificationresult/verified https://developer.apple.com/documentation/storekit/product/purchaseresult

Some Example:

import StoreKit

class StoreManager: NSObject, ObservableObject { // product purchase Request func purchase(_ product: SKProduct) async throws { // purchase request let result = try await product.purchase()

    switch result {
    case .success(let verification):
        // verify
        switch verification {
        case .verified(let transaction):
            // verification success: process purchase
            print("Purchase Verified: \(transaction)")
            await transaction.finish()

        case .unverified:
            // verification failed
            print("Purchase Unverified")
        }

    case .userCancelled:
        // canceled by user
        print("User cancelled the purchase")

    default:
        // etc
        print("Purchase Failed")
    }
}

}

https://github.com/dooboolab-community/react-native-iap/blob/main/ios/RNIapIosSk2.swift#L725

let result = try await product.purchase(options: options) switch result { case .success(let verification): debugMessage("Purchase Successful")

                    // Check whether the transaction is verified. If it isn't,
                    // this function rethrows the verification error.
                    let transaction = try **checkVerified**(verification)

https://github.com/dooboolab-community/react-native-iap/blob/2ab100377dbc17c1383531e24f054ef1028d947d/ios/IapSerializationUtils.swift#L181

https://github.com/dooboolab-community/react-native-iap/blob/2ab100377dbc17c1383531e24f054ef1028d947d/src/types/appleSk2.ts#L160

dmk3141618 commented 7 months ago

Oh I got it, I need both of Server Side and Application Side. Just Storekit2 is more simple than Storekit1. So I need all of App Store Server API, App Store Server Notification, ...

dmk3141618 commented 7 months ago

Just Apple removed this process. application side verification process. https://react-native-iap.dooboolab.com/docs/api-reference/methods/ios/validate-receipt-ios.

dmk3141618 commented 7 months ago

verificationResponseIOS is JWS. It is Json Web Token. Header.Payload.Signiture So... That's it. verify through jwt util and it is right JWT, then it means validated. So we can convince this info.

Anyway I could decode this verificationResponseIOS using this code.

const jwt = require('jsonwebtoken'); try { const decoded = jwt.decode(verificationResponseIOS); console.log(decoded); } catch (err) { console.log('Error decoding decodeJSONWebSignatureIETF_RFC_7515 info:', err); }

// decode info signed by the App Store according to the JSON Web Signature (JWS) IETF RFC 7515 specification. // The three components in the string are a header, a payload, and a signature, in that order. // To read the header, Base64 URL-decode it and use a JWSDecodedHeader object to access the information. Use the information in the header to verify the signature.

PatriciaSauer commented 1 week ago

Hi @dmk3141618 could you please explain step by step what I need to do? So transactionReceipt is empty but verificationResultIOS is indeed set for me. Do I need some backend validation or don't I need it anymore? I think I am not getting your description about what needs to be done. Any help would be appreciated. Thanks in advance!