From facb369dd3b99d67727c25a8e3d0aa39f4a46c5d Mon Sep 17 00:00:00 2001 From: yijiexu Date: Mon, 6 Jul 2020 15:56:59 -0700 Subject: [PATCH 01/13] Fix crash caused by missing on-device App Store receipt --- .../ios/Classes/FIAPReceiptManager.m | 15 +++++++++------ .../store_kit_wrappers/sk_receipt_manager.dart | 10 +++++++--- .../sk_methodchannel_apis_test.dart | 14 ++++++++++++++ 3 files changed, 30 insertions(+), 9 deletions(-) diff --git a/packages/in_app_purchase/ios/Classes/FIAPReceiptManager.m b/packages/in_app_purchase/ios/Classes/FIAPReceiptManager.m index 92872d91234e..a159546671ef 100644 --- a/packages/in_app_purchase/ios/Classes/FIAPReceiptManager.m +++ b/packages/in_app_purchase/ios/Classes/FIAPReceiptManager.m @@ -16,18 +16,21 @@ @implementation FIAPReceiptManager - (NSString *)retrieveReceiptWithError:(FlutterError **)error { NSURL *receiptURL = [[NSBundle mainBundle] appStoreReceiptURL]; - NSData *receipt = [self getReceiptData:receiptURL]; + NSError *error; + NSData *receipt = [self getReceiptData:receiptURL error:&error]; if (!receipt) { - *error = [FlutterError errorWithCode:@"storekit_no_receipt" - message:@"Cannot find receipt for the current main bundle." - details:nil]; + return nil; + } + if (error) { + *error = [FlutterError errorWithCode:[[NSString alloc] initWithFormat:@"%li", error.code]; + message:error.domain details:error.userInfo]; 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/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..276733903bd2 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,12 @@ 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( - '-[InAppPurchasePlugin retrieveReceiptData:result:]'); + static Future retrieveReceiptData() async { + try { + return await channel.invokeMethod( + '-[InAppPurchasePlugin retrieveReceiptData:result:]'); + } catch (_) { + rethrow; + } } } 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:]': From 3a1c70b0ab807df21972916609473fc29383efbc Mon Sep 17 00:00:00 2001 From: yijiexu Date: Mon, 6 Jul 2020 16:03:19 -0700 Subject: [PATCH 02/13] Update changelog --- packages/in_app_purchase/CHANGELOG.md | 3 +++ packages/in_app_purchase/pubspec.yaml | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/packages/in_app_purchase/CHANGELOG.md b/packages/in_app_purchase/CHANGELOG.md index c159b094fb47..a558cd8838b9 100644 --- a/packages/in_app_purchase/CHANGELOG.md +++ b/packages/in_app_purchase/CHANGELOG.md @@ -1,3 +1,6 @@ +## 0.3.4+2 +* iOS: Fix treating missing App Store receipt as an exception. + ## 0.3.4+1 * iOS: Fix the bug that `SKPaymentQueueWrapper.transactions` doesn't return all transactions. diff --git a/packages/in_app_purchase/pubspec.yaml b/packages/in_app_purchase/pubspec.yaml index 58f8e1174618..96432507a7af 100644 --- a/packages/in_app_purchase/pubspec.yaml +++ b/packages/in_app_purchase/pubspec.yaml @@ -1,7 +1,7 @@ name: in_app_purchase description: A Flutter plugin for in-app purchases. Exposes APIs for making in-app purchases through the App Store and Google Play. homepage: https://github.com/flutter/plugins/tree/master/packages/in_app_purchase -version: 0.3.4+1 +version: 0.3.4+2 dependencies: async: ^2.0.8 From 2f68d7a0983754c48a44d4a7be3aa6e91d35bc53 Mon Sep 17 00:00:00 2001 From: yijiexu Date: Mon, 6 Jul 2020 16:21:32 -0700 Subject: [PATCH 03/13] Fix redefination error --- packages/in_app_purchase/ios/Classes/FIAPReceiptManager.m | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/in_app_purchase/ios/Classes/FIAPReceiptManager.m b/packages/in_app_purchase/ios/Classes/FIAPReceiptManager.m index a159546671ef..a0dea0d9ea24 100644 --- a/packages/in_app_purchase/ios/Classes/FIAPReceiptManager.m +++ b/packages/in_app_purchase/ios/Classes/FIAPReceiptManager.m @@ -16,14 +16,14 @@ @implementation FIAPReceiptManager - (NSString *)retrieveReceiptWithError:(FlutterError **)error { NSURL *receiptURL = [[NSBundle mainBundle] appStoreReceiptURL]; - NSError *error; - NSData *receipt = [self getReceiptData:receiptURL error:&error]; + NSError *err; + NSData *receipt = [self getReceiptData:receiptURL error:&err]; if (!receipt) { return nil; } if (error) { - *error = [FlutterError errorWithCode:[[NSString alloc] initWithFormat:@"%li", error.code]; - message:error.domain details:error.userInfo]; + *error = [FlutterError errorWithCode:[[NSString alloc] initWithFormat:@"%li", err.code]; + message:error.domain details:err.userInfo]; return nil; } return [receipt base64EncodedStringWithOptions:kNilOptions]; From ebf622e471d54a4925a101dee0bf8d09221235f8 Mon Sep 17 00:00:00 2001 From: Yijie Xu Date: Tue, 21 Jul 2020 11:46:40 -0700 Subject: [PATCH 04/13] Use the method that handles exceptions --- packages/in_app_purchase/ios/Classes/FIAPReceiptManager.m | 6 +++--- .../lib/src/store_kit_wrappers/sk_receipt_manager.dart | 8 ++------ 2 files changed, 5 insertions(+), 9 deletions(-) diff --git a/packages/in_app_purchase/ios/Classes/FIAPReceiptManager.m b/packages/in_app_purchase/ios/Classes/FIAPReceiptManager.m index a0dea0d9ea24..91dbaf7123d8 100644 --- a/packages/in_app_purchase/ios/Classes/FIAPReceiptManager.m +++ b/packages/in_app_purchase/ios/Classes/FIAPReceiptManager.m @@ -18,14 +18,14 @@ - (NSString *)retrieveReceiptWithError:(FlutterError **)error { NSURL *receiptURL = [[NSBundle mainBundle] appStoreReceiptURL]; NSError *err; NSData *receipt = [self getReceiptData:receiptURL error:&err]; - if (!receipt) { - return nil; - } if (error) { *error = [FlutterError errorWithCode:[[NSString alloc] initWithFormat:@"%li", err.code]; message:error.domain details:err.userInfo]; return nil; } + if (!receipt) { + return nil; + } return [receipt base64EncodedStringWithOptions:kNilOptions]; } 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 276733903bd2..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 @@ -15,11 +15,7 @@ class SKReceiptManager { /// 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() async { - try { - return await channel.invokeMethod( - '-[InAppPurchasePlugin retrieveReceiptData:result:]'); - } catch (_) { - rethrow; - } + return await channel.invokeMethod( + '-[InAppPurchasePlugin retrieveReceiptData:result:]'); } } From b863b7e043afda301e3e5e1e3ccf9cd1e534cecd Mon Sep 17 00:00:00 2001 From: Yijie Xu Date: Tue, 21 Jul 2020 12:13:21 -0700 Subject: [PATCH 05/13] Handle receipt exceptions --- .../lib/src/in_app_purchase/app_store_connection.dart | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) 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..c419dd12807d 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 @@ -82,7 +82,7 @@ class AppStoreConnection implements InAppPurchaseConnection { List pastPurchases = []; try { - String receiptData = await _observer.getReceiptData(); + String receiptData = await getReceiptData(); final List restoredTransactions = await _observer.getRestoredTransactions( queue: _skPaymentQueueWrapper, @@ -124,7 +124,7 @@ class AppStoreConnection implements InAppPurchaseConnection { @override Future refreshPurchaseVerificationData() async { await SKRequestMaker().startRefreshReceiptRequest(); - String receipt = await SKReceiptManager.retrieveReceiptData(); + String receipt = await getReceiptData(); return PurchaseVerificationData( localVerificationData: receipt, serverVerificationData: receipt, From fd3b5c4e18eb6fb1300ff06a8d7b63a89ec9ba6e Mon Sep 17 00:00:00 2001 From: Yijie Xu Date: Wed, 22 Jul 2020 11:34:12 -0700 Subject: [PATCH 06/13] Fixing the build error --- packages/in_app_purchase/ios/Classes/FIAPReceiptManager.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/in_app_purchase/ios/Classes/FIAPReceiptManager.m b/packages/in_app_purchase/ios/Classes/FIAPReceiptManager.m index 91dbaf7123d8..376b9c435a51 100644 --- a/packages/in_app_purchase/ios/Classes/FIAPReceiptManager.m +++ b/packages/in_app_purchase/ios/Classes/FIAPReceiptManager.m @@ -19,7 +19,7 @@ - (NSString *)retrieveReceiptWithError:(FlutterError **)error { NSError *err; NSData *receipt = [self getReceiptData:receiptURL error:&err]; if (error) { - *error = [FlutterError errorWithCode:[[NSString alloc] initWithFormat:@"%li", err.code]; + *error = [FlutterError errorWithCode:[[NSString alloc] initWithFormat:@"%li", (long)err.code] message:error.domain details:err.userInfo]; return nil; } From 75016aaecaee0435d1a1db0c39c61671b4d71744 Mon Sep 17 00:00:00 2001 From: Yijie Xu Date: Wed, 22 Jul 2020 12:17:10 -0700 Subject: [PATCH 07/13] Fix typo --- packages/in_app_purchase/ios/Classes/FIAPReceiptManager.m | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/in_app_purchase/ios/Classes/FIAPReceiptManager.m b/packages/in_app_purchase/ios/Classes/FIAPReceiptManager.m index 376b9c435a51..741b21af2d97 100644 --- a/packages/in_app_purchase/ios/Classes/FIAPReceiptManager.m +++ b/packages/in_app_purchase/ios/Classes/FIAPReceiptManager.m @@ -18,9 +18,9 @@ - (NSString *)retrieveReceiptWithError:(FlutterError **)error { NSURL *receiptURL = [[NSBundle mainBundle] appStoreReceiptURL]; NSError *err; NSData *receipt = [self getReceiptData:receiptURL error:&err]; - if (error) { + if (err) { *error = [FlutterError errorWithCode:[[NSString alloc] initWithFormat:@"%li", (long)err.code] - message:error.domain details:err.userInfo]; + message:err.domain details:err.userInfo]; return nil; } if (!receipt) { From 781a7c1215a2c89be84defcb21f514d30e954d51 Mon Sep 17 00:00:00 2001 From: Yijie Xu Date: Wed, 22 Jul 2020 12:56:58 -0700 Subject: [PATCH 08/13] Formatting --- .../lib/src/in_app_purchase/app_store_connection.dart | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) 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 c419dd12807d..ec0740cc813c 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 @@ -82,7 +82,7 @@ class AppStoreConnection implements InAppPurchaseConnection { List pastPurchases = []; try { - String receiptData = await getReceiptData(); + String receiptData = await _observer.getReceiptData(); final List restoredTransactions = await _observer.getRestoredTransactions( queue: _skPaymentQueueWrapper, @@ -124,11 +124,15 @@ class AppStoreConnection implements InAppPurchaseConnection { @override Future refreshPurchaseVerificationData() async { await SKRequestMaker().startRefreshReceiptRequest(); - String receipt = await getReceiptData(); + try { + String receipt = await KReceiptManager.retrieveReceiptData(); return PurchaseVerificationData( localVerificationData: receipt, serverVerificationData: receipt, source: IAPSource.AppStore); + } catch (e) { + return null; + } } /// Query the product detail list. From cef1071fb5452bab93c85865d29410a7cd3bf1d0 Mon Sep 17 00:00:00 2001 From: Yijie Xu Date: Wed, 22 Jul 2020 15:49:31 -0700 Subject: [PATCH 09/13] Fix typo --- .../lib/src/in_app_purchase/app_store_connection.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 ec0740cc813c..a67067d303e4 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 @@ -125,7 +125,7 @@ class AppStoreConnection implements InAppPurchaseConnection { Future refreshPurchaseVerificationData() async { await SKRequestMaker().startRefreshReceiptRequest(); try { - String receipt = await KReceiptManager.retrieveReceiptData(); + String receipt = await SKReceiptManager.retrieveReceiptData(); return PurchaseVerificationData( localVerificationData: receipt, serverVerificationData: receipt, From 45c868ccb9c6e8f55eb11d6e9550914d520a09b8 Mon Sep 17 00:00:00 2001 From: Yijie Xu Date: Wed, 22 Jul 2020 16:30:19 -0700 Subject: [PATCH 10/13] Use flutter format instead of dartfmt --- packages/in_app_purchase/ios/Classes/FIAPReceiptManager.m | 3 ++- .../lib/src/in_app_purchase/app_store_connection.dart | 8 ++++---- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/packages/in_app_purchase/ios/Classes/FIAPReceiptManager.m b/packages/in_app_purchase/ios/Classes/FIAPReceiptManager.m index 741b21af2d97..3ce362fba5b6 100644 --- a/packages/in_app_purchase/ios/Classes/FIAPReceiptManager.m +++ b/packages/in_app_purchase/ios/Classes/FIAPReceiptManager.m @@ -20,7 +20,8 @@ - (NSString *)retrieveReceiptWithError:(FlutterError **)error { 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]; + message:err.domain + details:err.userInfo]; return nil; } if (!receipt) { 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 a67067d303e4..0a3877206406 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 @@ -126,10 +126,10 @@ class AppStoreConnection implements InAppPurchaseConnection { await SKRequestMaker().startRefreshReceiptRequest(); try { String receipt = await SKReceiptManager.retrieveReceiptData(); - return PurchaseVerificationData( - localVerificationData: receipt, - serverVerificationData: receipt, - source: IAPSource.AppStore); + return PurchaseVerificationData( + localVerificationData: receipt, + serverVerificationData: receipt, + source: IAPSource.AppStore); } catch (e) { return null; } From 4e163c90b3d38d6a1317aab9469bc4f60e7b5946 Mon Sep 17 00:00:00 2001 From: Yijie Xu Date: Wed, 22 Jul 2020 16:52:24 -0700 Subject: [PATCH 11/13] Fix failing test targets --- packages/in_app_purchase/ios/Tests/Stubs.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/in_app_purchase/ios/Tests/Stubs.m b/packages/in_app_purchase/ios/Tests/Stubs.m index 58b77c14127d..ba1f62a31986 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]; } From b2f3fab79e40d2d6561af107c8be1ad58801b61b Mon Sep 17 00:00:00 2001 From: Yijie Xu Date: Wed, 22 Jul 2020 17:04:15 -0700 Subject: [PATCH 12/13] Fix formatting --- packages/in_app_purchase/ios/Tests/Stubs.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/in_app_purchase/ios/Tests/Stubs.m b/packages/in_app_purchase/ios/Tests/Stubs.m index ba1f62a31986..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 error:(NSError **)error{ +- (NSData *)getReceiptData:(NSURL *)url error:(NSError **)error { NSString *originalString = [NSString stringWithFormat:@"test"]; return [[NSData alloc] initWithBase64EncodedString:originalString options:kNilOptions]; } From 1c143b9afc199dc97316cebfcdc8deb4e1795c8d Mon Sep 17 00:00:00 2001 From: Yijie Xu Date: Thu, 30 Jul 2020 13:33:29 -0700 Subject: [PATCH 13/13] Add print --- packages/in_app_purchase/CHANGELOG.md | 9 ++++++++- .../lib/src/in_app_purchase/app_store_connection.dart | 3 +++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/packages/in_app_purchase/CHANGELOG.md b/packages/in_app_purchase/CHANGELOG.md index a558cd8838b9..97adac9d72e9 100644 --- a/packages/in_app_purchase/CHANGELOG.md +++ b/packages/in_app_purchase/CHANGELOG.md @@ -1,5 +1,12 @@ +## 0.3.4+3 + +* Update package:e2e reference to use the local version in the flutter/plugins + repository. + ## 0.3.4+2 -* iOS: Fix treating missing App Store receipt as an exception. + +* Update package:e2e reference to use the local version in the flutter/plugins + repository. ## 0.3.4+1 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 0a3877206406..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 @@ -131,6 +131,9 @@ class AppStoreConnection implements InAppPurchaseConnection { 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; } }