Skip to content

Commit 13eb63f

Browse files
[camera_web] Fixed crashing bug on camera_web 0.3.5 for Safari (#10595)
On certain browsers (Safari), getting `facingMode` on video track capabilities is not supported. The code first checks if `facingMode` is available on `MediaTrackSettings` using `facingModeNullable` but when the code checks for facingMode on `MediaTrackCapabilities`, it uses the non nullable `facingMode` getter instead of `facingModeNullable`. This causes a crash and the camera isn't initialized correctly. This is a blocker for reliably deploying camera_web 0.3.5 which enables people to use WASM with camera functionality. Fixes flutter/flutter#155210 ## Testing Tested on Safari on Mac and iPhone with camera initialization - camera now successfully initializes where it previously failed. ## Pre-Review Checklist **Note**: The Flutter team is currently trialing the use of [Gemini Code Assist for GitHub](https://developers.google.com/gemini-code-assist/docs/review-github-code). Comments from the `gemini-code-assist` bot should not be taken as authoritative feedback from the Flutter team. If you find its comments useful you can update your code accordingly, but if you are unsure or disagree with the feedback, please feel free to wait for a Flutter team member's review for guidance on which automated comments should be addressed. [^1]: Regular contributors who have demonstrated familiarity with the repository guidelines only need to comment if the PR is not auto-exempted by repo tooling.
1 parent bdd29b6 commit 13eb63f

File tree

6 files changed

+57
-6
lines changed

6 files changed

+57
-6
lines changed

packages/camera/camera_web/CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,8 @@
1+
## 0.3.5+3
2+
3+
* Fixes camera initialization failure on Safari by fixing a null check operator error using
4+
a nullable getter and null safe practices.
5+
16
## 0.3.5+2
27

38
* Fixes camera initialization failure on Firefox Android by using `{video: true}` instead

packages/camera/camera_web/example/integration_test/camera_service_test.dart

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -708,6 +708,29 @@ void main() {
708708

709709
expect(facingMode, isNull);
710710
});
711+
712+
testWidgets('returns null '
713+
'when the facing mode setting is empty and '
714+
'the facingMode capability is null', (WidgetTester tester) async {
715+
mockVideoTrack.getSettings = () {
716+
return createJSInteropWrapper(FakeMediaTrackSettings())
717+
as web.MediaTrackSettings;
718+
}.toJS;
719+
mockVideoTrack.getCapabilities = () {
720+
return createJSInteropWrapper(FakeMediaTrackCapabilities())
721+
as web.MediaTrackCapabilities;
722+
}.toJS;
723+
724+
when(
725+
jsUtil.hasProperty(videoTrack, 'getCapabilities'.toJS),
726+
).thenReturn(true);
727+
728+
final String? facingMode = cameraService.getFacingModeForVideoTrack(
729+
videoTrack,
730+
);
731+
732+
expect(facingMode, isNull);
733+
});
711734
});
712735
});
713736

packages/camera/camera_web/example/integration_test/helpers/mocks.dart

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -284,3 +284,23 @@ class MockEventStreamProvider<T extends web.Event> extends Mock
284284
as ElementStream<T>;
285285
}
286286
}
287+
288+
/// A fake [web.MediaTrackCapabilities] where facingMode is null/undefined.
289+
///
290+
/// Used to test null-safe handling when the browser doesn't provide
291+
/// the facingMode capability.
292+
@JSExport()
293+
class FakeMediaTrackCapabilities {
294+
// Dummy property required by @JSExport
295+
bool get dummy => true;
296+
}
297+
298+
/// A fake [web.MediaTrackSettings] where facingMode is null/undefined.
299+
///
300+
/// Used to test null-safe handling when the browser doesn't provide
301+
/// the facingMode capability.
302+
@JSExport()
303+
class FakeMediaTrackSettings {
304+
// Dummy property required by @JSExport
305+
bool get dummy => true;
306+
}

packages/camera/camera_web/lib/src/camera_service.dart

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -200,11 +200,11 @@ class CameraService {
200200

201201
// A list of facing mode capabilities as
202202
// the camera may support multiple facing modes.
203-
final List<String> facingModeCapabilities = videoTrackCapabilities
204-
.facingMode
205-
.toDart
206-
.map((JSString e) => e.toDart)
207-
.toList();
203+
final List<String> facingModeCapabilities =
204+
videoTrackCapabilities.facingModeNullable?.toDart
205+
.map((JSString e) => e.toDart)
206+
.toList() ??
207+
<String>[];
208208

209209
if (facingModeCapabilities.isNotEmpty) {
210210
final String facingModeCapability = facingModeCapabilities.first;

packages/camera/camera_web/lib/src/pkg_web_tweaks.dart

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,9 @@ extension NonStandardFieldsOnMediaTrackCapabilities on MediaTrackCapabilities {
3131

3232
@JS('torch')
3333
external JSArray<JSBoolean>? get torchNullable;
34+
35+
@JS('facingMode')
36+
external JSArray<JSString>? get facingModeNullable;
3437
}
3538

3639
/// Adds missing fields to [MediaTrackSettings]

packages/camera/camera_web/pubspec.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ name: camera_web
22
description: A Flutter plugin for getting information about and controlling the camera on Web.
33
repository: https://github.com/flutter/packages/tree/main/packages/camera/camera_web
44
issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+camera%22
5-
version: 0.3.5+2
5+
version: 0.3.5+3
66

77
environment:
88
sdk: ^3.8.0

0 commit comments

Comments
 (0)