diff --git a/packages/in_app_purchase/CHANGELOG.md b/packages/in_app_purchase/CHANGELOG.md index 3f6bd8e7829e..97adac9d72e9 100644 --- a/packages/in_app_purchase/CHANGELOG.md +++ b/packages/in_app_purchase/CHANGELOG.md @@ -1,3 +1,8 @@ +## 0.3.4+3 + +* Update package:e2e reference to use the local version in the flutter/plugins + repository. + ## 0.3.4+2 * Update package:e2e reference to use the local version in the flutter/plugins diff --git a/packages/in_app_purchase/ios/Classes/FIAPReceiptManager.m b/packages/in_app_purchase/ios/Classes/FIAPReceiptManager.m index 92872d91234e..3ce362fba5b6 100644 --- a/packages/in_app_purchase/ios/Classes/FIAPReceiptManager.m +++ b/packages/in_app_purchase/ios/Classes/FIAPReceiptManager.m @@ -16,18 +16,22 @@ @implementation FIAPReceiptManager - (NSString *)retrieveReceiptWithError:(FlutterError **)error { NSURL *receiptURL = [[NSBundle mainBundle] appStoreReceiptURL]; - NSData *receipt = [self getReceiptData:receiptURL]; + NSError *err; + NSData *receipt = [self getReceiptData:receiptURL error:&err]; + if (err) { + *error = [FlutterError errorWithCode:[[NSString alloc] initWithFormat:@"%li", (long)err.code] + message:err.domain + details:err.userInfo]; + return nil; + } if (!receipt) { - *error = [FlutterError errorWithCode:@"storekit_no_receipt" - message:@"Cannot find receipt for the current main bundle." - details:nil]; return nil; } return [receipt base64EncodedStringWithOptions:kNilOptions]; } -- (NSData *)getReceiptData:(NSURL *)url { - return [NSData dataWithContentsOfURL:url]; +- (NSData *)getReceiptData:(NSURL *)url error:(NSError **)error { + return [NSData dataWithContentsOfURL:url options:NSDataReadingMappedIfSafe error:error]; } @end diff --git a/packages/in_app_purchase/ios/Tests/Stubs.m b/packages/in_app_purchase/ios/Tests/Stubs.m index 58b77c14127d..6f85781e5765 100644 --- a/packages/in_app_purchase/ios/Tests/Stubs.m +++ b/packages/in_app_purchase/ios/Tests/Stubs.m @@ -257,7 +257,7 @@ - (instancetype)initWithMap:(NSDictionary *)map { @implementation FIAPReceiptManagerStub : FIAPReceiptManager -- (NSData *)getReceiptData:(NSURL *)url { +- (NSData *)getReceiptData:(NSURL *)url error:(NSError **)error { NSString *originalString = [NSString stringWithFormat:@"test"]; return [[NSData alloc] initWithBase64EncodedString:originalString options:kNilOptions]; } diff --git a/packages/in_app_purchase/lib/src/in_app_purchase/app_store_connection.dart b/packages/in_app_purchase/lib/src/in_app_purchase/app_store_connection.dart index da6fc7417585..f96b2797d6b7 100644 --- a/packages/in_app_purchase/lib/src/in_app_purchase/app_store_connection.dart +++ b/packages/in_app_purchase/lib/src/in_app_purchase/app_store_connection.dart @@ -124,11 +124,18 @@ class AppStoreConnection implements InAppPurchaseConnection { @override Future refreshPurchaseVerificationData() async { await SKRequestMaker().startRefreshReceiptRequest(); - String receipt = await SKReceiptManager.retrieveReceiptData(); - return PurchaseVerificationData( - localVerificationData: receipt, - serverVerificationData: receipt, - source: IAPSource.AppStore); + try { + String receipt = await SKReceiptManager.retrieveReceiptData(); + return PurchaseVerificationData( + localVerificationData: receipt, + serverVerificationData: receipt, + source: IAPSource.AppStore); + } catch (e) { + print( + 'Something is wrong while fetching the receipt, this normally happens when the app is ' + 'running on a simulator: $e'); + return null; + } } /// Query the product detail list. diff --git a/packages/in_app_purchase/lib/src/store_kit_wrappers/sk_receipt_manager.dart b/packages/in_app_purchase/lib/src/store_kit_wrappers/sk_receipt_manager.dart index 85af9dedc7c3..bed9f09182d9 100644 --- a/packages/in_app_purchase/lib/src/store_kit_wrappers/sk_receipt_manager.dart +++ b/packages/in_app_purchase/lib/src/store_kit_wrappers/sk_receipt_manager.dart @@ -14,8 +14,8 @@ class SKReceiptManager { /// There are 2 ways to do so. Either validate locally or validate with App Store. /// For more details on how to validate the receipt data, you can refer to Apple's document about [`About Receipt Validation`](https://developer.apple.com/library/archive/releasenotes/General/ValidateAppStoreReceipt/Introduction.html#//apple_ref/doc/uid/TP40010573-CH105-SW1). /// If the receipt is invalid or missing, you can use [SKRequestMaker.startRefreshReceiptRequest] to request a new receipt. - static Future retrieveReceiptData() { - return channel.invokeMethod( + static Future retrieveReceiptData() async { + return await channel.invokeMethod( '-[InAppPurchasePlugin retrieveReceiptData:result:]'); } } diff --git a/packages/in_app_purchase/test/store_kit_wrappers/sk_methodchannel_apis_test.dart b/packages/in_app_purchase/test/store_kit_wrappers/sk_methodchannel_apis_test.dart index c8da68ab823a..0e522e3bbe88 100644 --- a/packages/in_app_purchase/test/store_kit_wrappers/sk_methodchannel_apis_test.dart +++ b/packages/in_app_purchase/test/store_kit_wrappers/sk_methodchannel_apis_test.dart @@ -6,6 +6,7 @@ import 'package:flutter/services.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:in_app_purchase/src/channel.dart'; import 'package:in_app_purchase/store_kit_wrappers.dart'; +import 'package:test/test.dart' show TypeMatcher; import 'sk_test_stub_objects.dart'; void main() { @@ -76,6 +77,12 @@ void main() { String receiptData = await SKReceiptManager.retrieveReceiptData(); expect(receiptData, 'receipt data'); }); + + test('should get null receipt if any exceptions are raised', () async { + fakeIOSPlatform.getReceiptFailTest = true; + expect(() async => SKReceiptManager.retrieveReceiptData(), + throwsA(TypeMatcher())); + }); }); group('sk_payment_queue', () { @@ -128,11 +135,15 @@ class FakeIOSPlatform { FakeIOSPlatform() { channel.setMockMethodCallHandler(onMethodCall); getProductRequestFailTest = false; + getReceiptFailTest = false; } // get product request List startProductRequestParam; bool getProductRequestFailTest; + // get receipt request + bool getReceiptFailTest; + // refresh receipt request int refreshReceipt = 0; Map refreshReceiptParam; @@ -161,6 +172,9 @@ class FakeIOSPlatform { return Future.sync(() {}); // receipt manager case '-[InAppPurchasePlugin retrieveReceiptData:result:]': + if (getReceiptFailTest) { + throw ("some arbitrary error"); + } return Future.value('receipt data'); // payment queue case '-[SKPaymentQueue canMakePayments:]':