Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[image_picker_macos] macOS native image picker #8079

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
1d8ec6c
chore(example): update outdated macOS example using Flutter build mac…
EchoEllet Oct 2, 2024
6ba3c14
feat(image_picker_macos): add support for native macOS image picker
EchoEllet Nov 13, 2024
c98699f
chore: generate pigeons and mocks with the latest dev dependencies
EchoEllet Nov 14, 2024
f420c91
chore: format Swift generated file Messages.g.swift
EchoEllet Nov 14, 2024
3f49936
chore: restore backticks of file_selector link
EchoEllet Nov 14, 2024
31c4f55
chore: update supported macOS version from 10.11 to 10.14 for image_p…
EchoEllet Nov 14, 2024
abd926c
chore: use getVideo() instead of the soft-deprecated pickVideo() in u…
EchoEllet Nov 14, 2024
75badd9
chore: update outdated TODOs as they moved to https://github.com/flut…
EchoEllet Nov 14, 2024
200cb10
test: add minor test for pickVideo
EchoEllet Nov 14, 2024
d1bee0a
chore: run dart format for Dart generated files
EchoEllet Nov 14, 2024
30fd055
chore: 'try' precede 'await' in ImagePickerImpl.swift
EchoEllet Nov 14, 2024
5edff64
chore: hardcode the supportsPHPicker() name to fix CI warnings
EchoEllet Nov 14, 2024
0aaf366
chore: remove @visibleForTesting from supportsPHPicker
EchoEllet Jan 2, 2025
527ac48
chore: remove unnecessary assertions from NSImage.compressed
EchoEllet Jan 2, 2025
b10b41f
refactor: require quality as not nil in shouldCompressImage to avoid …
EchoEllet Jan 2, 2025
0caa390
chore: remove unnecessary assertion from imageFileExt
EchoEllet Jan 2, 2025
b6582fe
chore: extract duplicated createTestImage from ImageCompressTests and…
EchoEllet Jan 2, 2025
c531757
feat: improve error handling, avoid hardcoding string error codes, us…
EchoEllet Jan 4, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion packages/image_picker/image_picker/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
## NEXT
## 1.1.3

* Updates minimum supported SDK version to Flutter 3.22/Dart 3.4.
* Updates README to include a reference to the macOS PHPicker feature.

## 1.1.2

Expand Down
13 changes: 12 additions & 1 deletion packages/image_picker/image_picker/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,7 @@ encourage the community to build packages that implement

#### macOS installation

Since the macOS implementation uses `file_selector`, you will need to
Since the macOS implementation uses `file_selector` by default, you will need to
add a filesystem access
[entitlement](https://flutter.dev/to/macos-entitlements):

Expand All @@ -162,6 +162,17 @@ add a filesystem access
<true/>
```

This setup is still required when using the [macOS PHPicker](#macos-phpicker) on **macOS 12 and older versions**, since it's only supported on **macOS 13+** and will fallback to the `file_selector` implementation.

#### macOS PHPicker

To use the [macOS native image picker](https://developer.apple.com/documentation/photokit/phpickerviewcontroller) which is supported on **macOS 13 and newer versions**,
refer to the [image_picker_macos PHPicker](https://pub.dev/packages/image_picker_macos#phpicker) section.

* **on macOS 13 and newer versions**: If this feature is used, the
filesystem access entitlement in the [macOS installation](#macos-installation) is not required.
* **on macOS 12 and older versions**: This feature is unsupported and will fallback to `file_selector` implementation, the filesystem access entitlement in the [macOS installation](#macos-installation) is required.

### Example

<?code-excerpt "readme_excerpts.dart (Pick)"?>
Expand Down
2 changes: 1 addition & 1 deletion packages/image_picker/image_picker/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ description: Flutter plugin for selecting images from the Android and iOS image
library, and taking new pictures with the camera.
repository: https://github.com/flutter/packages/tree/main/packages/image_picker/image_picker
issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+image_picker%22
version: 1.1.2
version: 1.1.3

environment:
sdk: ^3.4.0
Expand Down
3 changes: 2 additions & 1 deletion packages/image_picker/image_picker_macos/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
## NEXT
## 0.3.0

* Updates minimum supported SDK version to Flutter 3.22/Dart 3.4.
* Adds macOS 13+ PHPicker functionality (optional and disabled by default).

## 0.2.1+1

Expand Down
41 changes: 37 additions & 4 deletions packages/image_picker/image_picker_macos/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,44 @@

A macOS implementation of [`image_picker`][1].

## PHPicker

macOS 13.0 and newer versions supports native image picking via [PHPickerViewController][5].

To use this feature, add the following code to your app before calling any `image_picker` APIs:

<?code-excerpt "main.dart (phpicker-example)"?>
```dart
import 'package:image_picker_macos/image_picker_macos.dart';
import 'package:image_picker_platform_interface/image_picker_platform_interface.dart';
// ···
final ImagePickerPlatform imagePickerImplementation =
ImagePickerPlatform.instance;
if (imagePickerImplementation is ImagePickerMacOS) {
imagePickerImplementation.useMacOSPHPicker = true;
}
```

This implementation depends on the photos in the [Photos for macOS App][6],
if the user didn't open the app or import any photos to the app,
they will see: `No photos` or `No Photos or Videos` message even if they
have them as files on their desktop. The macOS Photos app supports importing images from an iOS device.

> [!NOTE]
> This feature is only supported on **macOS 13.0 and newer versions**, on older versions it will fallback to using [`file_selector`][3] if enabled.
> By defaults it's disabled on all versions.

## Limitations

`ImageSource.camera` is not supported unless a `cameraDelegate` is set.

### pickImage()
The arguments `maxWidth`, `maxHeight`, and `imageQuality` are not currently supported.
The arguments `maxWidth`, `maxHeight`, `imageQuality`, and `limit` are only supported when using the [PHPicker](#phpicker) implementation; they are not available in the default [file_selector][5] implementation.

The argument `requestFullMetadata` is unsupported on macOS.

### pickVideo()
The argument `maxDuration` is not currently supported.
The argument `maxDuration` is not supported even when using the [PHPicker](#phpicker) implementation.

## Usage

Expand All @@ -25,14 +54,18 @@ should add it to your `pubspec.yaml` as usual.

### Entitlements

This package is currently implemented using [`file_selector`][3], so you will
need to add a read-only file acces [entitlement][4]:
This package’s default implementation relies on [file_selector][3],
which requires the following read-only file access entitlement:
```xml
<key>com.apple.security.files.user-selected.read-only</key>
<true/>
```

If you're using the [PHPicker](#phpicker) and require at **least macOS 13** to run the app, this entitlement is not required.

[1]: https://pub.dev/packages/image_picker
[2]: https://flutter.dev/to/endorsed-federated-plugin
[3]: https://pub.dev/packages/file_selector
[4]: https://flutter.dev/to/macos-entitlements
[5]: https://developer.apple.com/documentation/photokit/phpickerviewcontroller
[6]: https://www.apple.com/in/macos/photos/
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

import 'package:example/main.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:image_picker_macos/image_picker_macos.dart';
import 'package:image_picker_platform_interface/image_picker_platform_interface.dart';
import 'package:integration_test/integration_test.dart';

ImagePickerMacOS get requireMacOSImplementation {
final ImagePickerPlatform imagePickerImplementation =
ImagePickerPlatform.instance;
if (imagePickerImplementation is! ImagePickerMacOS) {
fail('Expected the implementation to be $ImagePickerMacOS');
}
return imagePickerImplementation;
}

void main() {
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
group('example', () {
testWidgets(
'Pressing the PHPicker toggle button updates it correctly',
(WidgetTester tester) async {
final ImagePickerMacOS imagePickerImplementation =
requireMacOSImplementation;
expect(imagePickerImplementation.useMacOSPHPicker, false,
reason: 'The default is to not using PHPicker');

await tester.pumpWidget(const MyApp());
final Finder togglePHPickerFinder =
find.byTooltip('toggle macOS PHPPicker');
expect(togglePHPickerFinder, findsOneWidget);

await tester.tap(togglePHPickerFinder);
expect(imagePickerImplementation.useMacOSPHPicker, true,
reason: 'Pressing the toggle button should update it correctly');

await tester.tap(togglePHPickerFinder);
expect(imagePickerImplementation.useMacOSPHPicker, false,
reason: 'Pressing the toggle button should update it correctly');
},
);
});
}
51 changes: 51 additions & 0 deletions packages/image_picker/image_picker_macos/example/lib/main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,22 @@ import 'dart:async';
import 'dart:io';

import 'package:flutter/material.dart';
// #docregion phpicker-example
import 'package:image_picker_macos/image_picker_macos.dart';
import 'package:image_picker_platform_interface/image_picker_platform_interface.dart';
// #enddocregion phpicker-example
import 'package:mime/mime.dart';
import 'package:video_player/video_player.dart';

void main() {
// Set to use macOS PHPicker.
// #docregion phpicker-example
final ImagePickerPlatform imagePickerImplementation =
ImagePickerPlatform.instance;
if (imagePickerImplementation is ImagePickerMacOS) {
imagePickerImplementation.useMacOSPHPicker = true;
}
// #enddocregion phpicker-example
runApp(const MyApp());
}

Expand Down Expand Up @@ -385,6 +396,46 @@ class _MyHomePageState extends State<MyHomePage> {
child: const Icon(Icons.videocam),
),
),
Padding(
padding: const EdgeInsets.only(top: 16.0),
child: FloatingActionButton(
onPressed: () {
void showSnackbarText(String text) {
ScaffoldMessenger.of(context)
..clearSnackBars()
..showSnackBar(
SnackBar(content: Text(text)),
);
}

if (_picker is! ImagePickerMacOS) {
throw StateError(
'Expected the implementation to be $ImagePickerMacOS but was ${_picker.runtimeType}');
}

if (_picker.useMacOSPHPicker) {
_picker.useMacOSPHPicker = false;
setState(() {});
showSnackbarText('Switched to file_picker implementation.');
} else {
_picker.useMacOSPHPicker = true;
setState(() {});
showSnackbarText(
'Switched to macOS PHPPicker implementation.');
}
},
tooltip: 'toggle macOS PHPPicker',
child: () {
if (_picker is ImagePickerMacOS) {
return _picker.useMacOSPHPicker
? const Icon(Icons.apple)
: const Icon(Icons.file_open);
}
throw StateError(
'Expected the implementation to be $ImagePickerMacOS but was ${_picker.runtimeType}');
}(),
),
),
],
),
);
Expand Down
Loading
Loading