Skip to content
This repository was archived by the owner on Feb 22, 2023. It is now read-only.

Commit df6da95

Browse files
authored
[in_app_purchase] Make sure unsupported userInfo doesn't crash App (#5111)
1 parent 5566960 commit df6da95

File tree

4 files changed

+85
-8
lines changed

4 files changed

+85
-8
lines changed

packages/in_app_purchase/in_app_purchase_storekit/CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
## 0.3.0+4
2+
3+
* Ensures that `NSError` instances with an unexpected value for the `userInfo` field don't crash the app, but send an explanatory message instead.
4+
15
## 0.3.0+3
26

37
* Implements transaction caching for StoreKit ensuring transactions are delivered to the Flutter client.

packages/in_app_purchase/in_app_purchase_storekit/example/ios/RunnerTests/TranslatorTests.m

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,56 @@ - (void)testError {
158158
XCTAssertEqualObjects(map, self.errorMap);
159159
}
160160

161+
- (void)testErrorWithNSNumberAsUserInfo {
162+
NSError *error = [NSError errorWithDomain:SKErrorDomain code:3 userInfo:@{@"key" : @42}];
163+
NSDictionary *expectedMap =
164+
@{@"domain" : SKErrorDomain, @"code" : @3, @"userInfo" : @{@"key" : @42}};
165+
NSDictionary *map = [FIAObjectTranslator getMapFromNSError:error];
166+
XCTAssertEqualObjects(expectedMap, map);
167+
}
168+
169+
- (void)testErrorWithMultipleUnderlyingErrors {
170+
NSError *underlyingErrorOne = [NSError errorWithDomain:SKErrorDomain code:2 userInfo:nil];
171+
NSError *underlyingErrorTwo = [NSError errorWithDomain:SKErrorDomain code:1 userInfo:nil];
172+
NSError *mainError = [NSError
173+
errorWithDomain:SKErrorDomain
174+
code:3
175+
userInfo:@{@"underlyingErrors" : @[ underlyingErrorOne, underlyingErrorTwo ]}];
176+
NSDictionary *expectedMap = @{
177+
@"domain" : SKErrorDomain,
178+
@"code" : @3,
179+
@"userInfo" : @{
180+
@"underlyingErrors" : @[
181+
@{@"domain" : SKErrorDomain, @"code" : @2, @"userInfo" : @{}},
182+
@{@"domain" : SKErrorDomain, @"code" : @1, @"userInfo" : @{}}
183+
]
184+
}
185+
};
186+
NSDictionary *map = [FIAObjectTranslator getMapFromNSError:mainError];
187+
XCTAssertEqualObjects(expectedMap, map);
188+
}
189+
190+
- (void)testErrorWithUnsupportedUserInfo {
191+
NSError *error = [NSError errorWithDomain:SKErrorDomain
192+
code:3
193+
userInfo:@{@"user_info" : [[NSObject alloc] init]}];
194+
NSDictionary *expectedMap = @{
195+
@"domain" : SKErrorDomain,
196+
@"code" : @3,
197+
@"userInfo" : @{
198+
@"user_info" : [NSString
199+
stringWithFormat:
200+
@"Unable to encode native userInfo object of type %@ to map. Please submit an "
201+
@"issue at https://github.com/flutter/flutter/issues/new with the title "
202+
@"\"[in_app_purchase_storekit] Unable to encode userInfo of type %@\" and add "
203+
@"reproduction steps and the error details in the description field.",
204+
[NSObject class], [NSObject class]]
205+
}
206+
};
207+
NSDictionary *map = [FIAObjectTranslator getMapFromNSError:error];
208+
XCTAssertEqualObjects(expectedMap, map);
209+
}
210+
161211
- (void)testLocaleToMap {
162212
if (@available(iOS 10.0, *)) {
163213
NSLocale *system = [[NSLocale alloc] initWithLocaleIdentifier:@"en_US"];

packages/in_app_purchase/in_app_purchase_storekit/ios/Classes/FIAObjectTranslator.m

Lines changed: 30 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -167,20 +167,43 @@ + (NSDictionary *)getMapFromNSError:(NSError *)error {
167167
if (!error) {
168168
return nil;
169169
}
170+
170171
NSMutableDictionary *userInfo = [NSMutableDictionary new];
171172
for (NSErrorUserInfoKey key in error.userInfo) {
172173
id value = error.userInfo[key];
173-
if ([value isKindOfClass:[NSError class]]) {
174-
userInfo[key] = [FIAObjectTranslator getMapFromNSError:value];
175-
} else if ([value isKindOfClass:[NSURL class]]) {
176-
userInfo[key] = [value absoluteString];
177-
} else {
178-
userInfo[key] = value;
179-
}
174+
userInfo[key] = [FIAObjectTranslator encodeNSErrorUserInfo:value];
180175
}
181176
return @{@"code" : @(error.code), @"domain" : error.domain ?: @"", @"userInfo" : userInfo};
182177
}
183178

179+
+ (id)encodeNSErrorUserInfo:(id)value {
180+
if ([value isKindOfClass:[NSError class]]) {
181+
return [FIAObjectTranslator getMapFromNSError:value];
182+
} else if ([value isKindOfClass:[NSURL class]]) {
183+
return [value absoluteString];
184+
} else if ([value isKindOfClass:[NSNumber class]]) {
185+
return value;
186+
} else if ([value isKindOfClass:[NSString class]]) {
187+
return value;
188+
} else if ([value isKindOfClass:[NSArray class]]) {
189+
NSMutableArray *errors = [[NSMutableArray alloc] init];
190+
for (id error in value) {
191+
[errors addObject:[FIAObjectTranslator encodeNSErrorUserInfo:error]];
192+
}
193+
return errors;
194+
} else {
195+
return [NSString
196+
stringWithFormat:
197+
@"Unable to encode native userInfo object of type %@ to map. Please submit an issue at "
198+
@"https://github.com/flutter/flutter/issues/new with the title "
199+
@"\"[in_app_purchase_storekit] "
200+
@"Unable to encode userInfo of type %@\" and add reproduction steps and the error "
201+
@"details in "
202+
@"the description field.",
203+
[value class], [value class]];
204+
}
205+
}
206+
184207
+ (NSDictionary *)getMapFromSKStorefront:(SKStorefront *)storefront {
185208
if (!storefront) {
186209
return nil;

packages/in_app_purchase/in_app_purchase_storekit/pubspec.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ name: in_app_purchase_storekit
22
description: An implementation for the iOS platform of the Flutter `in_app_purchase` plugin. This uses the StoreKit Framework.
33
repository: https://github.com/flutter/plugins/tree/main/packages/in_app_purchase/in_app_purchase_storekit
44
issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+in_app_purchase%22
5-
version: 0.3.0+3
5+
version: 0.3.0+4
66

77
environment:
88
sdk: ">=2.14.0 <3.0.0"

0 commit comments

Comments
 (0)