- Notifications
You must be signed in to change notification settings - Fork1
A macOS platform implementation of image_picker using the native system picker instead of file_selector
License
CompileKernel/native-image-picker-macos
Folders and files
| Name | Name | Last commit message | Last commit date | |
|---|---|---|---|---|
Repository files navigation
A macOS platform implementation ofimage_pickerusing the native system picker instead of the system open file dialog.
This package is an alternative toimage_picker_macoswhich usesfile_selector.
Note
This native picker depends on the photos in thePhotos for MacOS App, which uses theApple PhotosUI Picker, also known as PHPicker.
| Default picker | Native picker |
|---|---|
![]() | ![]() |
- 🚀Seamless Integration
Effortlessly integrates with theimage_pickerpackage. Switch seamlessly betweenimage_picker_macosand this native platform implementation without modifying existing code. - 🔒No Permissions or Setup Required
Requires no runtime permission prompts or entitlement configuration. Everything works out of the box. - 📱macOS Photos App
Enables picking images from the macOS Photos app, integrating with the Apple ecosystem and supporting photo imports from connected iOS devices. - 🛠️Supports Image Options
Adds support for image arguments likemaxWidth,maxHeight, andimageQuality—featuresnot currently supported inimage_picker_macos.
Run the following command to add the dependencies:
$ flutter pub add image_picker image_picker_macos native_image_picker_macos
image_picker: The app-facing package for the Image Picker plugin which specifies the API used by Flutter apps.image_picker_macos: The default macOS implementation ofimage_picker, built onfile_selectorand usingNSOpenPanelwith appropriate file type filters set. Lacks image resizing/compression options but supports older macOS versions.native_image_picker_macos: A macOS implementation ofimage_picker, built onPHPickerViewControllerwhich depends on thePhotos for macOS App. Supports image resizing/compression options. Requires macOS 13.0+.
Using bothimage_picker_macos andnative_image_picker_macos can enable user-level opt-in to switch between implementations if the user prefers to pick images from the photos app or the file system.
The platform implementationimage_picker_macos is required to ensure compatibility with macOS versions before 13.0, which is used as a fallback, in that case, it's necessary tosetupimage_picker_macos.
Tip
After registering this implementation as outlined in theUsage section, you canuse theimage_picker plugin as usual.
By default, this package doesn't replace the default implementation ofimage_picker for macOS to avoid conflict withimage_picker_macos.
This implementation supports macOS 13 Ventura and later.
To apply this package only in case it's supported on the current macOS version:
Future<void>main()async {WidgetsFlutterBinding.ensureInitialized();awaitNativeImagePickerMacOS.registerWithIfSupported();// ADD THIS LINErunApp(constMainApp());}
To checks if the current implementation ofimage_picker isnative_image_picker_macos:
finalbool isRegistered=NativeImagePickerMacOS.isRegistered();// ORimport'package:image_picker_platform_interface/image_picker_platform_interface.dart';finalbool isRegistered=ImagePickerPlatform.instanceisNativeImagePickerMacOS;
To checks if the current macOS version supports this implementation:
finalbool isSupported=awaitNativeImagePickerMacOS.isSupported();// Returns false on non-macOS platforms or if PHPicker is not supported on the current macOS version.
To switch betweenimage_picker_macos andnative_image_picker_macos implementations:
// NOTE: This code assumes the current target platform is macOS and native_image_picker_macos implementation is supported.import'package:image_picker_macos/image_picker_macos.dart';import'package:native_image_picker_macos/native_image_picker_macos.dart';// To switch to image_picker_macos (supported on all macOS versions):ImagePickerMacOS.registerWith();// To switch to native_image_picker_macos (supported on macOS 13 and above):NativeImagePickerMacOS.registerWith();
To open the macOS photos app:
awaitNativeImagePickerMacOS.instanceOrNull?.openPhotosApp();// ORfinalImagePickerPlatform imagePickerImplementation=ImagePickerPlatform.instance;if (imagePickerImplementationisNativeImagePickerMacOS) {await imagePickerImplementation.openPhotosApp();}
Tip
You can useNativeImagePickerMacOS.registerWith() to register this implementation. However, this bypasses platform checks, whichmay result in runtime errors if the current platform is not macOS or if the macOS version is unsupported. Instead, useregisterWithIfSupported() if uncertain.
Refer to theexample main.dart for a full usage example.
This package usespigeon for platform communication with the platform host andmockito for mocking in unit tests andswift-format for formatting the Swift code.
$ dart run pigeon --input pigeons/messages.dart# To generate the required Dart and host-language code.$ dart run build_runner build --delete-conflicting-outputs# To generate the mock classes.$ swift-format format --in-place --recursive macos/native_image_picker_macos/Sources/native_image_picker_macos example/macos/Runner example/macos/RunnerTests example/macos/RunnerUITests# To format the Swift code.$ dart format.# To format the Dart code.$ (cd example/macos&& xcodebuildtest -workspace Runner.xcworkspace -scheme Runner -configuration Debug -quiet)# To run the native macOS unit tests.$ fluttertest# To run the Flutter unit tests.
- Flutter repo style guide.
- Flutter repo plugin tests.
- Flutter repo writing effective tests.
- Flutter developing plugin packages.
- Flutter testing plugins,Flutter plugins in Flutter tests andFlutter mock dependencies using Mockito.
- Pigeon example README.
- Effective Dart.
- PHPickerViewController.
Contributions are welcome. File issues to theGitHub repo.
- Similarly to
image_picker_macos,ImageSource.camerais not supportedunless acameraDelegateis set. - Similarly to
image_picker_macos, themaxDurationargument inpickVideois unsupported and will be silently ignored.
This functionality was originally proposed as apull request toimage_picker_macos, but it was later decided to split it into a community package which is unendorsed.
Ask a question about using the package.
Tip
With this approach, you can effectively test this platform implementation with the existing packages that useimage_picker APIs. All platform-specific calls toNativeImagePickerMacOS should use the instance fromImagePickerPlatform.instance instead of creating a newNativeImagePickerMacOS to work.
To override the methods implementation for unit testing, add the dev dependencies:
mockito(ormocktail): for mocking the instance methods ofNativeImagePickerMacOS.image_picker_platform_interface: for overriding the instance ofImagePickerPlatformwith the mock instance.build_runner: for creating the generated Dart files.plugin_platform_interface: SinceImagePickerPlatformextendsPlatformInterface, it's required to apply the mixinMockPlatformInterfaceMixinto the mock ofNativeImagePickerMacOStoignore an assertation failure that enforces the usage ofextendsinstead ofimplements, since mock classes need to extendMockand implement the real class.
$ flutter pub add dev:mockito dev:image_picker_platform_interface dev:build_runner dev:plugin_platform_interface# Add them as dev-dependenciesIn your test file, add this annotation somewhere:
import'package:mockito/annotations.dart';import'package:mockito/mockito.dart';import'package:native_image_picker_macos/native_image_picker_macos.dart';@GenerateNiceMocks([MockSpec<NativeImagePickerMacOS>()])
Generate theMockNativeImagePickerMacOS by running:
$ dart run build_runner build --delete-conflicting-outputs
Create a new instance ofMockNativeImagePickerMacOS and override the instance ofImagePickerPlatform to every test:
import'package:image_picker_platform_interface/image_picker_platform_interface.dart';import'package:flutter_test/flutter_test.dart';voidmain() {TestWidgetsFlutterBinding.ensureInitialized();lateMockNativeImagePickerMacOS mockNativeImagePickerMacOS;setUp(() { mockNativeImagePickerMacOS=MockNativeImagePickerMacOS();ImagePickerPlatform.instance= mockNativeImagePickerMacOS; });// Your tests, example:testWidgets('pressing the open photos button calls openPhotosApp from $NativeImagePickerMacOS', (WidgetTester tester)async {await tester .pumpWidget(constExampleWidget());// REPLACE WITH THE TARGET WIDGETfinal openPhotosFinder= find.text('Open Photos App');// REPLACE WITH THE BUTTON TEXTexpect(openPhotosFinder, findsOneWidget);// Assuming the openPhotosApp call will success.when(mockNativeImagePickerMacOS.openPhotosApp()) .thenAnswer((_)async=>true);await tester.tap(openPhotosFinder);await tester.pump();verify(mockNativeImagePickerMacOS.openPhotosApp()).called(1);verifyNoMoreInteractions(mockNativeImagePickerMacOS); }, );// ...}
However, if you run the tests, you will get the following error:
Assertion failed: "Platform interfaces must not be implemented with `implements`"And that is because by default, all plugin platform interfaces that inherit fromPlatformInterface mustextends and notimplements it to avoid breaking changes (adding new methods to platform interfaces are not considered breaking changes).
And mock classes mustimplements the real class rather thanextends them, a solution is toprovide the mixinMockPlatformInterfaceMixin fromplugin_platform_interface that will override this check:
import'package:plugin_platform_interface/plugin_platform_interface.dart';// This doesn't work yet since MockNativeImagePickerMacOS is generated, unlike the mocktail package.classMockNativeImagePickerMacOSextendsMockwithMockPlatformInterfaceMixinimplementsNativeImagePickerMacOS {}
And sinceMockNativeImagePickerMacOS is generated, we need a new class that extends the base mock and provides theMockPlatformInterfaceMixin forplugin_platform_interface to not throw the assertion failure:
@GenerateNiceMocks([MockSpec<NativeImagePickerMacOS>(as:Symbol('BaseMockNativeImagePickerMacOS'))])// This name should be different than MockNativeImagePickerMacOS for the mockito generation to successimport'<current-test-file-name>.mocks.dart';// REPLACE <current-test-file-name> with the current test file name without extensionimport'package:plugin_platform_interface/plugin_platform_interface.dart';classMockNativeImagePickerMacOSextendsBaseMockNativeImagePickerMacOSwithMockPlatformInterfaceMixin {}// Use MockNativeImagePickerMacOS instead of BaseMockNativeImagePickerMacOS for creating the mock of NativeImagePickerMacOS
Refer to theexample main_test.dart for the full example test.
Note
Refer to theFlutter documentation on mocking dependencies using Mockito for more details.
About
A macOS platform implementation of image_picker using the native system picker instead of file_selector
Topics
Resources
License
Code of conduct
Uh oh!
There was an error while loading.Please reload this page.
Stars
Watchers
Forks
Packages0
Uh oh!
There was an error while loading.Please reload this page.




