2.4.9
0.59.5
iOS
Should work in Simulator and Actual Device
Purchase works when building to an actual device (iPhone 8, iOS 12.2), but doesn't work in Simulator (iOS 12.2 iPhone XS).
Apple has rejected the app with:
We found that your in-app purchase products exhibited one or more bugs when reviewed on iPad running iOS 12.2 on Wi-Fi.
- Unable to purchase. When an event is created and proceeded to Buy Now button, it flashes without triggering any action.
Next Steps
When validating receipts on your server, your server needs to be able to handle a production-signed app getting its receipts from Apple’s test environment. The recommended approach is for your production server to always validate receipts against the production App Store first. If validation fails with the error code "Sandbox receipt used in production," you should validate against the test environment instead.
buyProduct call
const purchase = await RNIap.buyProduct('specialevent');
Fails with
{ [Error: Cannot connect to iTunes Store]
framesToPop: 1,
code: 'E_UNKNOWN',
domain: 'SKErrorDomain',
userInfo: { NSLocalizedDescription: 'Cannot connect to iTunes Store' },
nativeStackIOS:
[ '0 eventlive 0x000000010a267bb7 RCTJSErrorFromCodeMessageAndNSError + 135',
'1 eventlive 0x000000010a1b3403 __41-[RCTModuleMethod processMethodSignature]_block_invoke_2.129 + 179',
'2 eventlive 0x000000010a02d8de -[RNIapIos rejectPromisesForKey:code:message:error:] + 622',
'3 eventlive 0x000000010a030fd5 __45-[RNIapIos paymentQueue:updatedTransactions:]_block_invoke + 293',
'4 libdispatch.dylib 0x00000001137cedb5 _dispatch_client_callout + 8',
'5 libdispatch.dylib 0x00000001137dcd08 _dispatch_lane_barrier_sync_invoke_and_complete + 132',
'6 eventlive 0x000000010a030d67 -[RNIapIos paymentQueue:updatedTransactions:] + 1079',
'7 libdispatch.dylib 0x00000001137cdd7f _dispatch_call_block_and_release + 12',
'8 libdispatch.dylib 0x00000001137cedb5 _dispatch_client_callout + 8',
'9 libdispatch.dylib 0x00000001137dc080 _dispatch_main_queue_callback_4CF + 1540',
'10 CoreFoundation 0x000000010e8d28a9 __CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE__ + 9',
'11 CoreFoundation 0x000000010e8ccf56 __CFRunLoopRun + 2310',
'12 CoreFoundation 0x000000010e8cc302 CFRunLoopRunSpecific + 626',
'13 GraphicsServices 0x00000001171252fe GSEventRunModal + 65',
'14 UIKitCore 0x000000011b123ba2 UIApplicationMain + 140',
'15 eventlive 0x0000000109d527f0 main + 112',
'16 libdyld.dylib 0x0000000113843541 start + 1',
'17 ??? 0x0000000000000001 0x0 + 1' ],
line: 2125,
column: 26,
sourceURL: 'http://localhost:8081/index.bundle?platform=ios&dev=true&minify=false' }
Emulator & Real device
try {
const canMakePayments = await RNIap.initConnection();
const itemSkus = [
'specialevent',
];
const products = await RNIap.getProducts(itemSkus);
const purchase = await RNIap.buyProduct('specialevent');
} catch (err) {
console.log(err);
const subscription = RNIap.addAdditionalSuccessPurchaseListenerIOS(async (purchase) => {
await this.publishEvent(slug, purchase.transactionReceipt)
subscription.remove();
});
this.setState({ loading: false })
}
Since Apple has rejected the binary, the in-app-purchase is in "Developer action needed" state, however, purchase works on device in a sandbox, but rejects with the error above in simulator (which they use to test)
How do you know that they use simulator to test? Apple simulators have never worked with in app purchases, be it with this library, or any other of native library. Emulators don't support "StoreKit" library.
If they really are using simulators, you should let them know that it's not supported scenario.
Your code doesn't look right as well, it should be:
try {
const canMakePayments = await RNIap.initConnection();
const itemSkus = [
'specialevent',
];
const products = await RNIap.getProducts(itemSkus);
const purchase = await RNIap.buyProduct('specialevent');
await this.publishEvent(slug, purchase.transactionReceipt) /* added this */
} catch (err) {
console.log(err);
const subscription = RNIap.addAdditionalSuccessPurchaseListenerIOS(async (purchase) => {
await this.publishEvent(slug, purchase.transactionReceipt)
subscription.remove();
});
this.setState({ loading: false })
}
Thanks for a swift reply @ChrisEelmaa
I've had that line in my code, just removed it for clarity...
Ok so if it doesn't work in the simulator and they test on a real device, why else could it fail for them? Any ideas are appreciated... I can't really tell since it's working properly on my device.
Here's what they're suggesting in review:
Next Steps
When validating receipts on your server, your server needs to be able to handle a production-signed app getting its receipts from Apple’s test environment. The recommended approach is for your production server to always validate receipts against the production App Store first. If validation fails with the error code "Sandbox receipt used in production," you should validate against the test environment instead.
Resources
You can learn more about testing in-app purchase products in your development sandbox environment in App Store Connect Developer Help.
For more information on receipt validation, please see What url should I use to verify my receipt? in the In-App Purchase FAQ.
Learn how to generate a receipt validation code in App Store Connect Developer Help.
Could it mean we should use a different code and receipt verification rather than just RNIap.buyProduct ?
Your code looks OK, you don't need to change anything there.
It's hard to tell what's going on. Ideally you should always log all the activity around the payments and send it to your server along side with the device information, so it would be clear what was happening for specific client tried that tried to access in app purchase. If you are taking money from an user, you better have good diagnostics. (verbose/error)
WIthout seeing if apple reviewers got any error at all (and what device they used), I am not sure.
Are you doing any receipt verification in your backend? RNIap.buyProduct is enough, but you also need to do receipt verification in your backend in order to ensure that it is "legit" before giving user access to your app. (For example using this library https://github.com/voltrue2/in-app-purchase). This library takes care of the "production -> sandbox environment" fall back in case of receipt verification.
Thank you for explaining, @ChrisEelmaa
I'll add error reporting so next time hopefully they'll catch it on screenshot + will send along to the server.
Does buyProduct attempt validation by itself?
Or should I use
clearTransaction & buyProductWithoutFinishTransaction & validateReceiptIOS & finishTransaction
And handle production -> sandbox environment fall back on device ?
@mkrn The purchase shouldn't work in simulator. Also buyProductWithoutFinishTransaction is currently deprecated so does the finishTransaction.
Most helpful comment
@mkrn The purchase shouldn't work in
simulator. AlsobuyProductWithoutFinishTransactionis currently deprecated so does thefinishTransaction.