Skip to content

Commit 741d98b

Browse files
[camera] Remove @throw from iOS implementation
Using `@throw` in iOS code violates the style guide, so it shouldn't be done in the plugin as mechanism for communicating errors. More importantly, `NSError` is not intended to be used with `@throw`/`@catch`, and is causing issues when compiled with the iOS 17 SDK. This removes all use of `@throw`, and all `@catch (NSError* e)`, in favor of other methods of communicating errors. It explicitly does not try to fix all the other strange things about this code (having an `NSError` out-param in an init method, using Cocoa and NSURL error domains and codes for some reason), and instead preserves existing behavior as much as possible. In practice, none of these codepaths should ever actually happen (they indicate programming errors within the plugin, not unexpected runtime behavior), and all of this code will go away when converting to Pigeon anyway, so there's not much value in trying to unwind this structure further. Fixes flutter/flutter#135195
1 parent c070b0a commit 741d98b

File tree

6 files changed

+94
-92
lines changed

6 files changed

+94
-92
lines changed

packages/camera/camera_avfoundation/CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
## 0.9.13+6
2+
3+
* Fixes incorrect use of `NSError` that could cause crashes on launch.
4+
15
## 0.9.13+5
26

37
* Ignores audio samples until the first video sample arrives.

packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraPropertiesTests.m

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ - (void)testFLTGetFLTFlashModeForString {
1919
XCTAssertEqual(FLTFlashModeAuto, FLTGetFLTFlashModeForString(@"auto"));
2020
XCTAssertEqual(FLTFlashModeAlways, FLTGetFLTFlashModeForString(@"always"));
2121
XCTAssertEqual(FLTFlashModeTorch, FLTGetFLTFlashModeForString(@"torch"));
22-
XCTAssertThrows(FLTGetFLTFlashModeForString(@"unkwown"));
22+
XCTAssertEqual(FLTFlashModeInvalid, FLTGetFLTFlashModeForString(@"unknown"));
2323
}
2424

2525
- (void)testFLTGetAVCaptureFlashModeForFLTFlashMode {
@@ -34,27 +34,27 @@ - (void)testFLTGetAVCaptureFlashModeForFLTFlashMode {
3434
- (void)testFLTGetStringForFLTExposureMode {
3535
XCTAssertEqualObjects(@"auto", FLTGetStringForFLTExposureMode(FLTExposureModeAuto));
3636
XCTAssertEqualObjects(@"locked", FLTGetStringForFLTExposureMode(FLTExposureModeLocked));
37-
XCTAssertThrows(FLTGetStringForFLTExposureMode(-1));
37+
XCTAssertNil(FLTGetStringForFLTExposureMode(-1));
3838
}
3939

4040
- (void)testFLTGetFLTExposureModeForString {
4141
XCTAssertEqual(FLTExposureModeAuto, FLTGetFLTExposureModeForString(@"auto"));
4242
XCTAssertEqual(FLTExposureModeLocked, FLTGetFLTExposureModeForString(@"locked"));
43-
XCTAssertThrows(FLTGetFLTExposureModeForString(@"unknown"));
43+
XCTAssertEqual(FLTExposureModeInvalid, FLTGetFLTExposureModeForString(@"unknown"));
4444
}
4545

4646
#pragma mark - focus mode tests
4747

4848
- (void)testFLTGetStringForFLTFocusMode {
4949
XCTAssertEqualObjects(@"auto", FLTGetStringForFLTFocusMode(FLTFocusModeAuto));
5050
XCTAssertEqualObjects(@"locked", FLTGetStringForFLTFocusMode(FLTFocusModeLocked));
51-
XCTAssertThrows(FLTGetStringForFLTFocusMode(-1));
51+
XCTAssertNil(FLTGetStringForFLTFocusMode(-1));
5252
}
5353

5454
- (void)testFLTGetFLTFocusModeForString {
5555
XCTAssertEqual(FLTFocusModeAuto, FLTGetFLTFocusModeForString(@"auto"));
5656
XCTAssertEqual(FLTFocusModeLocked, FLTGetFLTFocusModeForString(@"locked"));
57-
XCTAssertThrows(FLTGetFLTFocusModeForString(@"unknown"));
57+
XCTAssertEqual(FLTFocusModeInvalid, FLTGetFLTFocusModeForString(@"unknown"));
5858
}
5959

6060
#pragma mark - resolution preset tests
@@ -67,7 +67,7 @@ - (void)testFLTGetFLTResolutionPresetForString {
6767
XCTAssertEqual(FLTResolutionPresetVeryHigh, FLTGetFLTResolutionPresetForString(@"veryHigh"));
6868
XCTAssertEqual(FLTResolutionPresetUltraHigh, FLTGetFLTResolutionPresetForString(@"ultraHigh"));
6969
XCTAssertEqual(FLTResolutionPresetMax, FLTGetFLTResolutionPresetForString(@"max"));
70-
XCTAssertThrows(FLTGetFLTFlashModeForString(@"unknown"));
70+
XCTAssertEqual(FLTResolutionPresetInvalid, FLTGetFLTResolutionPresetForString(@"unknown"));
7171
}
7272

7373
#pragma mark - video format tests
@@ -89,7 +89,7 @@ - (void)testFLTGetUIDeviceOrientationForString {
8989
XCTAssertEqual(UIDeviceOrientationLandscapeLeft,
9090
FLTGetUIDeviceOrientationForString(@"landscapeRight"));
9191
XCTAssertEqual(UIDeviceOrientationPortrait, FLTGetUIDeviceOrientationForString(@"portraitUp"));
92-
XCTAssertThrows(FLTGetUIDeviceOrientationForString(@"unknown"));
92+
XCTAssertEqual(UIDeviceOrientationUnknown, FLTGetUIDeviceOrientationForString(@"unknown"));
9393
}
9494

9595
- (void)testFLTGetStringForUIDeviceOrientation {

packages/camera/camera_avfoundation/ios/Classes/CameraProperties.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,9 @@ typedef NS_ENUM(NSInteger, FLTFlashMode) {
1717
FLTFlashModeAuto,
1818
FLTFlashModeAlways,
1919
FLTFlashModeTorch,
20+
// This should never occur; it indicates an unknown value was received over
21+
// the platform channel.
22+
FLTFlashModeInvalid,
2023
};
2124

2225
/**
@@ -39,6 +42,9 @@ extern AVCaptureFlashMode FLTGetAVCaptureFlashModeForFLTFlashMode(FLTFlashMode m
3942
typedef NS_ENUM(NSInteger, FLTExposureMode) {
4043
FLTExposureModeAuto,
4144
FLTExposureModeLocked,
45+
// This should never occur; it indicates an unknown value was received over
46+
// the platform channel.
47+
FLTExposureModeInvalid,
4248
};
4349

4450
/**
@@ -61,6 +67,9 @@ extern FLTExposureMode FLTGetFLTExposureModeForString(NSString *mode);
6167
typedef NS_ENUM(NSInteger, FLTFocusMode) {
6268
FLTFocusModeAuto,
6369
FLTFocusModeLocked,
70+
// This should never occur; it indicates an unknown value was received over
71+
// the platform channel.
72+
FLTFocusModeInvalid,
6473
};
6574

6675
/**
@@ -100,6 +109,9 @@ typedef NS_ENUM(NSInteger, FLTResolutionPreset) {
100109
FLTResolutionPresetVeryHigh,
101110
FLTResolutionPresetUltraHigh,
102111
FLTResolutionPresetMax,
112+
// This should never occur; it indicates an unknown value was received over
113+
// the platform channel.
114+
FLTResolutionPresetInvalid,
103115
};
104116

105117
/**

packages/camera/camera_avfoundation/ios/Classes/CameraProperties.m

Lines changed: 13 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -16,13 +16,7 @@ FLTFlashMode FLTGetFLTFlashModeForString(NSString *mode) {
1616
} else if ([mode isEqualToString:@"torch"]) {
1717
return FLTFlashModeTorch;
1818
} else {
19-
NSError *error = [NSError errorWithDomain:NSCocoaErrorDomain
20-
code:NSURLErrorUnknown
21-
userInfo:@{
22-
NSLocalizedDescriptionKey : [NSString
23-
stringWithFormat:@"Unknown flash mode %@", mode]
24-
}];
25-
@throw error;
19+
return FLTFlashModeInvalid;
2620
}
2721
}
2822

@@ -48,14 +42,11 @@ AVCaptureFlashMode FLTGetAVCaptureFlashModeForFLTFlashMode(FLTFlashMode mode) {
4842
return @"auto";
4943
case FLTExposureModeLocked:
5044
return @"locked";
45+
case FLTExposureModeInvalid:
46+
// This value should never actually be used.
47+
return nil;
5148
}
52-
NSError *error = [NSError errorWithDomain:NSCocoaErrorDomain
53-
code:NSURLErrorUnknown
54-
userInfo:@{
55-
NSLocalizedDescriptionKey : [NSString
56-
stringWithFormat:@"Unknown string for exposure mode"]
57-
}];
58-
@throw error;
49+
return nil;
5950
}
6051

6152
FLTExposureMode FLTGetFLTExposureModeForString(NSString *mode) {
@@ -64,13 +55,7 @@ FLTExposureMode FLTGetFLTExposureModeForString(NSString *mode) {
6455
} else if ([mode isEqualToString:@"locked"]) {
6556
return FLTExposureModeLocked;
6657
} else {
67-
NSError *error = [NSError errorWithDomain:NSCocoaErrorDomain
68-
code:NSURLErrorUnknown
69-
userInfo:@{
70-
NSLocalizedDescriptionKey : [NSString
71-
stringWithFormat:@"Unknown exposure mode %@", mode]
72-
}];
73-
@throw error;
58+
return FLTExposureModeInvalid;
7459
}
7560
}
7661

@@ -82,14 +67,11 @@ FLTExposureMode FLTGetFLTExposureModeForString(NSString *mode) {
8267
return @"auto";
8368
case FLTFocusModeLocked:
8469
return @"locked";
70+
case FLTFocusModeInvalid:
71+
// This value should never actually be used.
72+
return nil;
8573
}
86-
NSError *error = [NSError errorWithDomain:NSCocoaErrorDomain
87-
code:NSURLErrorUnknown
88-
userInfo:@{
89-
NSLocalizedDescriptionKey : [NSString
90-
stringWithFormat:@"Unknown string for focus mode"]
91-
}];
92-
@throw error;
74+
return nil;
9375
}
9476

9577
FLTFocusMode FLTGetFLTFocusModeForString(NSString *mode) {
@@ -98,13 +80,7 @@ FLTFocusMode FLTGetFLTFocusModeForString(NSString *mode) {
9880
} else if ([mode isEqualToString:@"locked"]) {
9981
return FLTFocusModeLocked;
10082
} else {
101-
NSError *error = [NSError errorWithDomain:NSCocoaErrorDomain
102-
code:NSURLErrorUnknown
103-
userInfo:@{
104-
NSLocalizedDescriptionKey : [NSString
105-
stringWithFormat:@"Unknown focus mode %@", mode]
106-
}];
107-
@throw error;
83+
return FLTFocusModeInvalid;
10884
}
10985
}
11086

@@ -120,14 +96,7 @@ UIDeviceOrientation FLTGetUIDeviceOrientationForString(NSString *orientation) {
12096
} else if ([orientation isEqualToString:@"portraitUp"]) {
12197
return UIDeviceOrientationPortrait;
12298
} else {
123-
NSError *error = [NSError
124-
errorWithDomain:NSCocoaErrorDomain
125-
code:NSURLErrorUnknown
126-
userInfo:@{
127-
NSLocalizedDescriptionKey :
128-
[NSString stringWithFormat:@"Unknown device orientation %@", orientation]
129-
}];
130-
@throw error;
99+
return UIDeviceOrientationUnknown;
131100
}
132101
}
133102

@@ -163,13 +132,7 @@ FLTResolutionPreset FLTGetFLTResolutionPresetForString(NSString *preset) {
163132
} else if ([preset isEqualToString:@"max"]) {
164133
return FLTResolutionPresetMax;
165134
} else {
166-
NSError *error = [NSError errorWithDomain:NSCocoaErrorDomain
167-
code:NSURLErrorUnknown
168-
userInfo:@{
169-
NSLocalizedDescriptionKey : [NSString
170-
stringWithFormat:@"Unknown resolution preset %@", preset]
171-
}];
172-
@throw error;
135+
return FLTResolutionPresetInvalid;
173136
}
174137
}
175138

packages/camera/camera_avfoundation/ios/Classes/FLTCam.m

Lines changed: 57 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -118,10 +118,16 @@ - (instancetype)initWithCameraName:(NSString *)cameraName
118118
error:(NSError **)error {
119119
self = [super init];
120120
NSAssert(self, @"super init cannot be nil");
121-
@try {
122-
_resolutionPreset = FLTGetFLTResolutionPresetForString(resolutionPreset);
123-
} @catch (NSError *e) {
124-
*error = e;
121+
_resolutionPreset = FLTGetFLTResolutionPresetForString(resolutionPreset);
122+
if (_resolutionPreset == FLTResolutionPresetInvalid) {
123+
*error = [NSError
124+
errorWithDomain:NSCocoaErrorDomain
125+
code:NSURLErrorUnknown
126+
userInfo:@{
127+
NSLocalizedDescriptionKey :
128+
[NSString stringWithFormat:@"Unknown resolution preset %@", resolutionPreset]
129+
}];
130+
return nil;
125131
}
126132
_enableAudio = enableAudio;
127133
_captureSessionQueue = captureSessionQueue;
@@ -162,7 +168,9 @@ - (instancetype)initWithCameraName:(NSString *)cameraName
162168
_motionManager = [[CMMotionManager alloc] init];
163169
[_motionManager startAccelerometerUpdates];
164170

165-
[self setCaptureSessionPreset:_resolutionPreset];
171+
if (![self setCaptureSessionPreset:_resolutionPreset withError:error]) {
172+
return nil;
173+
}
166174
[self updateOrientation];
167175

168176
return self;
@@ -337,7 +345,7 @@ - (NSString *)getTemporaryFilePathWithExtension:(NSString *)extension
337345
return file;
338346
}
339347

340-
- (void)setCaptureSessionPreset:(FLTResolutionPreset)resolutionPreset {
348+
- (BOOL)setCaptureSessionPreset:(FLTResolutionPreset)resolutionPreset withError:(NSError **)error {
341349
switch (resolutionPreset) {
342350
case FLTResolutionPresetMax:
343351
case FLTResolutionPresetUltraHigh:
@@ -382,17 +390,17 @@ - (void)setCaptureSessionPreset:(FLTResolutionPreset)resolutionPreset {
382390
_videoCaptureSession.sessionPreset = AVCaptureSessionPresetLow;
383391
_previewSize = CGSizeMake(352, 288);
384392
} else {
385-
NSError *error =
386-
[NSError errorWithDomain:NSCocoaErrorDomain
387-
code:NSURLErrorUnknown
388-
userInfo:@{
389-
NSLocalizedDescriptionKey :
390-
@"No capture session available for current capture session."
391-
}];
392-
@throw error;
393+
*error = [NSError errorWithDomain:NSCocoaErrorDomain
394+
code:NSURLErrorUnknown
395+
userInfo:@{
396+
NSLocalizedDescriptionKey :
397+
@"No capture session available for current capture session."
398+
}];
399+
return NO;
393400
}
394401
}
395402
_audioCaptureSession.sessionPreset = _videoCaptureSession.sessionPreset;
403+
return YES;
396404
}
397405

398406
- (void)captureOutput:(AVCaptureOutput *)output
@@ -726,11 +734,17 @@ - (void)resumeVideoRecordingWithResult:(FLTThreadSafeFlutterResult *)result {
726734

727735
- (void)lockCaptureOrientationWithResult:(FLTThreadSafeFlutterResult *)result
728736
orientation:(NSString *)orientationStr {
729-
UIDeviceOrientation orientation;
730-
@try {
731-
orientation = FLTGetUIDeviceOrientationForString(orientationStr);
732-
} @catch (NSError *e) {
733-
[result sendError:e];
737+
UIDeviceOrientation orientation = FLTGetUIDeviceOrientationForString(orientationStr);
738+
// "Unknown" should never be sent, so is used to represent an unexpected
739+
// value.
740+
if (orientation == UIDeviceOrientationUnknown) {
741+
[result sendError:[NSError errorWithDomain:NSCocoaErrorDomain
742+
code:NSURLErrorUnknown
743+
userInfo:@{
744+
NSLocalizedDescriptionKey : [NSString
745+
stringWithFormat:@"Unknown device orientation %@",
746+
orientationStr]
747+
}]];
734748
return;
735749
}
736750

@@ -749,11 +763,14 @@ - (void)unlockCaptureOrientationWithResult:(FLTThreadSafeFlutterResult *)result
749763
}
750764

751765
- (void)setFlashModeWithResult:(FLTThreadSafeFlutterResult *)result mode:(NSString *)modeStr {
752-
FLTFlashMode mode;
753-
@try {
754-
mode = FLTGetFLTFlashModeForString(modeStr);
755-
} @catch (NSError *e) {
756-
[result sendError:e];
766+
FLTFlashMode mode = FLTGetFLTFlashModeForString(modeStr);
767+
if (mode == FLTFlashModeInvalid) {
768+
[result sendError:[NSError errorWithDomain:NSCocoaErrorDomain
769+
code:NSURLErrorUnknown
770+
userInfo:@{
771+
NSLocalizedDescriptionKey : [NSString
772+
stringWithFormat:@"Unknown flash mode %@", modeStr]
773+
}]];
757774
return;
758775
}
759776
if (mode == FLTFlashModeTorch) {
@@ -800,11 +817,14 @@ - (void)setFlashModeWithResult:(FLTThreadSafeFlutterResult *)result mode:(NSStri
800817
}
801818

802819
- (void)setExposureModeWithResult:(FLTThreadSafeFlutterResult *)result mode:(NSString *)modeStr {
803-
FLTExposureMode mode;
804-
@try {
805-
mode = FLTGetFLTExposureModeForString(modeStr);
806-
} @catch (NSError *e) {
807-
[result sendError:e];
820+
FLTExposureMode mode = FLTGetFLTExposureModeForString(modeStr);
821+
if (mode == FLTExposureModeInvalid) {
822+
[result sendError:[NSError errorWithDomain:NSCocoaErrorDomain
823+
code:NSURLErrorUnknown
824+
userInfo:@{
825+
NSLocalizedDescriptionKey : [NSString
826+
stringWithFormat:@"Unknown exposure mode %@", modeStr]
827+
}]];
808828
return;
809829
}
810830
_exposureMode = mode;
@@ -830,11 +850,14 @@ - (void)applyExposureMode {
830850
}
831851

832852
- (void)setFocusModeWithResult:(FLTThreadSafeFlutterResult *)result mode:(NSString *)modeStr {
833-
FLTFocusMode mode;
834-
@try {
835-
mode = FLTGetFLTFocusModeForString(modeStr);
836-
} @catch (NSError *e) {
837-
[result sendError:e];
853+
FLTFocusMode mode = FLTGetFLTFocusModeForString(modeStr);
854+
if (mode == FLTFocusModeInvalid) {
855+
[result sendError:[NSError errorWithDomain:NSCocoaErrorDomain
856+
code:NSURLErrorUnknown
857+
userInfo:@{
858+
NSLocalizedDescriptionKey : [NSString
859+
stringWithFormat:@"Unknown focus mode %@", modeStr]
860+
}]];
838861
return;
839862
}
840863
_focusMode = mode;

packages/camera/camera_avfoundation/pubspec.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ name: camera_avfoundation
22
description: iOS implementation of the camera plugin.
33
repository: https://github.com/flutter/packages/tree/main/packages/camera/camera_avfoundation
44
issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+camera%22
5-
version: 0.9.13+5
5+
version: 0.9.13+6
66

77
environment:
88
sdk: ">=2.19.0 <4.0.0"

0 commit comments

Comments
 (0)