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

Commit dd2d739

Browse files
authored
[image_picker] Migrate image_picker to package:cross_file (#4073)
1 parent cf80430 commit dd2d739

File tree

7 files changed

+686
-115
lines changed

7 files changed

+686
-115
lines changed

packages/image_picker/image_picker/CHANGELOG.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,12 @@
1+
## 0.8.2
2+
3+
* Added new methods that return `package:cross_file` `XFile` instances. [Docs](https://pub.dev/documentation/cross_file/latest/index.html).
4+
* Deprecate methods that return `PickedFile` instances:
5+
* `getImage`: use **`pickImage`** instead.
6+
* `getVideo`: use **`pickVideo`** instead.
7+
* `getMultiImage`: use **`pickMultiImage`** instead.
8+
* `getLostData`: use **`retrieveLostData`** instead.
9+
110
## 0.8.1+4
211

312
* Fixes an issue where `preferredCameraDevice` option is not working for `getVideo` method.

packages/image_picker/image_picker/README.md

Lines changed: 24 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ First, add `image_picker` as a [dependency in your pubspec.yaml file](https://fl
1212
### iOS
1313

1414
Starting with version **0.8.1** the iOS implementation uses PHPicker to pick (multiple) images on iOS 14 or higher.
15-
As a result of implementing PHPicker it becomes impossible to pick HEIC images on the iOS simulator in iOS 14+. This is a known issue. Please test this on a real device, or test with non-HEIC images until Apple solves this issue.[63426347 - Apple known issue](https://www.google.com/search?q=63426347+apple&sxsrf=ALeKk01YnTMid5S0PYvhL8GbgXJ40ZS[…]t=gws-wiz&ved=0ahUKEwjKh8XH_5HwAhWL_rsIHUmHDN8Q4dUDCA8&uact=5)
15+
As a result of implementing PHPicker it becomes impossible to pick HEIC images on the iOS simulator in iOS 14+. This is a known issue. Please test this on a real device, or test with non-HEIC images until Apple solves this issue.[63426347 - Apple known issue](https://www.google.com/search?q=63426347+apple&sxsrf=ALeKk01YnTMid5S0PYvhL8GbgXJ40ZS[…]t=gws-wiz&ved=0ahUKEwjKh8XH_5HwAhWL_rsIHUmHDN8Q4dUDCA8&uact=5)
1616

1717
Add the following keys to your _Info.plist_ file, located in `<project root>/ios/Runner/Info.plist`:
1818

@@ -37,7 +37,19 @@ If you require your picked image to be stored permanently, it is your responsibi
3737
import 'package:image_picker/image_picker.dart';
3838
3939
...
40-
final PickedFile? pickedFile = await picker.getImage(source: ImageSource.camera);
40+
final ImagePicker _picker = ImagePicker();
41+
// Pick an image
42+
final XFile? image = await _picker.pickImage(source: ImageSource.gallery);
43+
// Capture a photo
44+
final XFile? photo = await _picker.pickImage(source: ImageSource.camera);
45+
// Pick a video
46+
final XFile? image = await _picker.pickVideo(source: ImageSource.gallery);
47+
// Capture a video
48+
final XFile? photo = await _picker.pickVideo(source: ImageSource.camera);
49+
// Pick multiple images
50+
final List<XFile>? images = await _picker.pickMultiImage(source: ImageSource.gallery);
51+
// Pick multiple photos
52+
final List<XFile>? photos = await _picker.pickMultiImage(source: ImageSource.camera);
4153
...
4254
```
4355

@@ -46,9 +58,9 @@ import 'package:image_picker/image_picker.dart';
4658
Android system -- although very rarely -- sometimes kills the MainActivity after the image_picker finishes. When this happens, we lost the data selected from the image_picker. You can use `retrieveLostData` to retrieve the lost data in this situation. For example:
4759

4860
```dart
49-
Future<void> retrieveLostData() async {
50-
final LostData response =
51-
await picker.getLostData();
61+
Future<void> getLostData() async {
62+
final LostDataResponse response =
63+
await picker.retrieveLostData();
5264
if (response.isEmpty) {
5365
return;
5466
}
@@ -68,65 +80,17 @@ Future<void> retrieveLostData() async {
6880

6981
There's no way to detect when this happens, so calling this method at the right place is essential. We recommend to wire this into some kind of start up check. Please refer to the example app to see how we used it.
7082

71-
On Android, `getLostData` will only get the last picked image when picking multiple images, see: [#84634](https://github.com/flutter/flutter/issues/84634).
83+
On Android, `retrieveLostData` will only get the last picked image when picking multiple images, see: [#84634](https://github.com/flutter/flutter/issues/84634).
7284

73-
## Deprecation warnings in `pickImage`, `pickVideo` and `LostDataResponse`
85+
## Migrating to 0.8.2+
7486

75-
Starting with version **0.6.7** of the image_picker plugin, the API of the plugin changed slightly to allow for web implementations to exist.
76-
77-
The **old methods that returned `dart:io` File objects were marked as deprecated**, and a new set of methods that return [`PickedFile` objects](https://pub.dev/documentation/image_picker_platform_interface/latest/image_picker_platform_interface/PickedFile-class.html) were introduced.
78-
79-
### How to migrate from to ^0.6.7
80-
81-
#### Instantiate the `ImagePicker`
82-
83-
The new ImagePicker API does not rely in static methods anymore, so the first thing you'll need to do is to create a new instance of the plugin where you need it:
84-
85-
```dart
86-
final _picker = ImagePicker();
87-
```
87+
Starting with version **0.8.2** of the image_picker plugin, new methods have been added for picking files that return `XFile` instances (from the [cross_file](https://pub.dev/packages/cross_file) package) rather than the plugin's own `PickedFile` instances. While the previous methods still exist, it is already recommended to start migrating over to their new equivalents. Eventually, `PickedFile` and the methods that return instances of it will be deprecated and removed.
8888

8989
#### Call the new methods
9090

91-
The new methods **receive the same parameters as before**, but they **return a `PickedFile`, instead of a `File`**. The `LostDataResponse` class has been replaced by the [`LostData` class](https://pub.dev/documentation/image_picker_platform_interface/latest/image_picker_platform_interface/LostData-class.html).
92-
9391
| Old API | New API |
9492
|---------|---------|
95-
| `File image = await ImagePicker.pickImage(...)` | `PickedFile image = await _picker.getImage(...)` |
96-
| `File video = await ImagePicker.pickVideo(...)` | `PickedFile video = await _picker.getVideo(...)` |
97-
| `LostDataResponse response = await ImagePicker.retrieveLostData()` | `LostData response = await _picker.getLostData()` |
98-
99-
#### `PickedFile` to `File`
100-
101-
If your app needs dart:io `File` objects to operate, you may transform `PickedFile` to `File` like so:
102-
103-
```dart
104-
final pickedFile = await _picker.getImage(...);
105-
final File file = File(pickedFile.path);
106-
```
107-
108-
You may also retrieve the bytes from the pickedFile directly if needed:
109-
110-
```dart
111-
final bytes = await pickedFile.readAsBytes();
112-
```
113-
114-
#### Getting ready for the web platform
115-
116-
Note that on the web platform (`kIsWeb == true`), `File` is not available, so the `path` of the `PickedFile` will point to a network resource instead:
117-
118-
```dart
119-
if (kIsWeb) {
120-
image = Image.network(pickedFile.path);
121-
} else {
122-
image = Image.file(File(pickedFile.path));
123-
}
124-
```
125-
126-
Alternatively, the code may be unified at the expense of memory utilization:
127-
128-
```dart
129-
image = Image.memory(await pickedFile.readAsBytes())
130-
```
131-
132-
Take a look at the changes to the `example` app introduced in version 0.6.7 to see the migration steps applied there.
93+
| `PickedFile image = await _picker.getImage(...)` | `XFile image = await _picker.pickImage(...)` |
94+
| `List<PickedFile> images = await _picker.getMultiImage(...)` | `List<XFile> images = await _picker.pickMultiImage(...)` |
95+
| `PickedFile video = await _picker.getVideo(...)` | `XFile video = await _picker.pickVideo(...)` |
96+
| `LostData response = await _picker.getLostData()` | `LostDataResponse response = await _picker.retrieveLostData()` |

packages/image_picker/image_picker/example/lib/main.dart

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -36,9 +36,9 @@ class MyHomePage extends StatefulWidget {
3636
}
3737

3838
class _MyHomePageState extends State<MyHomePage> {
39-
List<PickedFile>? _imageFileList;
39+
List<XFile>? _imageFileList;
4040

41-
set _imageFile(PickedFile? value) {
41+
set _imageFile(XFile? value) {
4242
_imageFileList = value == null ? null : [value];
4343
}
4444

@@ -54,7 +54,7 @@ class _MyHomePageState extends State<MyHomePage> {
5454
final TextEditingController maxHeightController = TextEditingController();
5555
final TextEditingController qualityController = TextEditingController();
5656

57-
Future<void> _playVideo(PickedFile? file) async {
57+
Future<void> _playVideo(XFile? file) async {
5858
if (file != null && mounted) {
5959
await _disposeVideoController();
6060
late VideoPlayerController controller;
@@ -84,14 +84,14 @@ class _MyHomePageState extends State<MyHomePage> {
8484
await _controller!.setVolume(0.0);
8585
}
8686
if (isVideo) {
87-
final PickedFile? file = await _picker.getVideo(
87+
final XFile? file = await _picker.pickVideo(
8888
source: source, maxDuration: const Duration(seconds: 10));
8989
await _playVideo(file);
9090
} else if (isMultiImage) {
9191
await _displayPickImageDialog(context!,
9292
(double? maxWidth, double? maxHeight, int? quality) async {
9393
try {
94-
final pickedFileList = await _picker.getMultiImage(
94+
final pickedFileList = await _picker.pickMultiImage(
9595
maxWidth: maxWidth,
9696
maxHeight: maxHeight,
9797
imageQuality: quality,
@@ -109,7 +109,7 @@ class _MyHomePageState extends State<MyHomePage> {
109109
await _displayPickImageDialog(context!,
110110
(double? maxWidth, double? maxHeight, int? quality) async {
111111
try {
112-
final pickedFile = await _picker.getImage(
112+
final pickedFile = await _picker.pickImage(
113113
source: source,
114114
maxWidth: maxWidth,
115115
maxHeight: maxHeight,
@@ -214,7 +214,7 @@ class _MyHomePageState extends State<MyHomePage> {
214214
}
215215

216216
Future<void> retrieveLostData() async {
217-
final LostData response = await _picker.getLostData();
217+
final LostDataResponse response = await _picker.retrieveLostData();
218218
if (response.isEmpty) {
219219
return;
220220
}

packages/image_picker/image_picker/lib/image_picker.dart

Lines changed: 144 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,8 @@
22
// Use of this source code is governed by a BSD-style license that can be
33
// found in the LICENSE file.
44

5-
// ignore_for_file: deprecated_member_use, deprecated_member_use_from_same_package
6-
75
import 'dart:async';
8-
96
import 'package:flutter/foundation.dart';
10-
117
import 'package:image_picker_platform_interface/image_picker_platform_interface.dart';
128

139
export 'package:image_picker_platform_interface/image_picker_platform_interface.dart'
@@ -17,7 +13,9 @@ export 'package:image_picker_platform_interface/image_picker_platform_interface.
1713
ImageSource,
1814
CameraDevice,
1915
LostData,
16+
LostDataResponse,
2017
PickedFile,
18+
XFile,
2119
RetrieveType;
2220

2321
/// Provides an easy way to pick an image/video from the image library,
@@ -61,6 +59,7 @@ class ImagePicker {
6159
/// the camera or photos gallery, no camera is available, plugin is already in use,
6260
/// temporary file could not be created (iOS only), plugin activity could not
6361
/// be allocated (Android only) or due to an unknown error.
62+
@Deprecated('Switch to using pickImage instead')
6463
Future<PickedFile?> getImage({
6564
required ImageSource source,
6665
double? maxWidth,
@@ -101,6 +100,7 @@ class ImagePicker {
101100
/// be allocated (Android only) or due to an unknown error.
102101
///
103102
/// See also [getImage] to allow users to only pick a single image.
103+
@Deprecated('Switch to using pickMultiImage instead')
104104
Future<List<PickedFile>?> getMultiImage({
105105
double? maxWidth,
106106
double? maxHeight,
@@ -135,6 +135,7 @@ class ImagePicker {
135135
/// temporary file could not be created and video could not be cached (iOS only),
136136
/// plugin activity could not be allocated (Android only) or due to an unknown error.
137137
///
138+
@Deprecated('Switch to using pickVideo instead')
138139
Future<PickedFile?> getVideo({
139140
required ImageSource source,
140141
CameraDevice preferredCameraDevice = CameraDevice.rear,
@@ -160,7 +161,146 @@ class ImagePicker {
160161
/// See also:
161162
/// * [LostData], for what's included in the response.
162163
/// * [Android Activity Lifecycle](https://developer.android.com/reference/android/app/Activity.html), for more information on MainActivity destruction.
164+
@Deprecated('Switch to using retrieveLostData instead')
163165
Future<LostData> getLostData() {
164166
return platform.retrieveLostData();
165167
}
168+
169+
/// Returns an [XFile] object wrapping the image that was picked.
170+
///
171+
/// The returned [XFile] is intended to be used within a single APP session. Do not save the file path and use it across sessions.
172+
///
173+
/// The `source` argument controls where the image comes from. This can
174+
/// be either [ImageSource.camera] or [ImageSource.gallery].
175+
///
176+
/// Where iOS supports HEIC images, Android 8 and below doesn't. Android 9 and above only support HEIC images if used
177+
/// in addition to a size modification, of which the usage is explained below.
178+
///
179+
/// If specified, the image will be at most `maxWidth` wide and
180+
/// `maxHeight` tall. Otherwise the image will be returned at it's
181+
/// original width and height.
182+
/// The `imageQuality` argument modifies the quality of the image, ranging from 0-100
183+
/// where 100 is the original/max quality. If `imageQuality` is null, the image with
184+
/// the original quality will be returned. Compression is only supported for certain
185+
/// image types such as JPEG and on Android PNG and WebP, too. If compression is not supported for the image that is picked,
186+
/// a warning message will be logged.
187+
///
188+
/// Use `preferredCameraDevice` to specify the camera to use when the `source` is [ImageSource.camera].
189+
/// The `preferredCameraDevice` is ignored when `source` is [ImageSource.gallery]. It is also ignored if the chosen camera is not supported on the device.
190+
/// Defaults to [CameraDevice.rear]. Note that Android has no documented parameter for an intent to specify if
191+
/// the front or rear camera should be opened, this function is not guaranteed
192+
/// to work on an Android device.
193+
///
194+
/// In Android, the MainActivity can be destroyed for various reasons. If that happens, the result will be lost
195+
/// in this call. You can then call [retrieveLostData] when your app relaunches to retrieve the lost data.
196+
///
197+
/// See also [pickMultiImage] to allow users to select multiple images at once.
198+
///
199+
/// The method could throw [PlatformException] if the app does not have permission to access
200+
/// the camera or photos gallery, no camera is available, plugin is already in use,
201+
/// temporary file could not be created (iOS only), plugin activity could not
202+
/// be allocated (Android only) or due to an unknown error.
203+
Future<XFile?> pickImage({
204+
required ImageSource source,
205+
double? maxWidth,
206+
double? maxHeight,
207+
int? imageQuality,
208+
CameraDevice preferredCameraDevice = CameraDevice.rear,
209+
}) {
210+
return platform.getImage(
211+
source: source,
212+
maxWidth: maxWidth,
213+
maxHeight: maxHeight,
214+
imageQuality: imageQuality,
215+
preferredCameraDevice: preferredCameraDevice,
216+
);
217+
}
218+
219+
/// Returns a [List<XFile>] object wrapping the images that were picked.
220+
///
221+
/// The returned [List<XFile>] is intended to be used within a single APP session. Do not save the file path and use it across sessions.
222+
///
223+
/// Where iOS supports HEIC images, Android 8 and below doesn't. Android 9 and above only support HEIC images if used
224+
/// in addition to a size modification, of which the usage is explained below.
225+
///
226+
/// This method is not supported in iOS versions lower than 14.
227+
///
228+
/// If specified, the images will be at most `maxWidth` wide and
229+
/// `maxHeight` tall. Otherwise the images will be returned at it's
230+
/// original width and height.
231+
/// The `imageQuality` argument modifies the quality of the images, ranging from 0-100
232+
/// where 100 is the original/max quality. If `imageQuality` is null, the images with
233+
/// the original quality will be returned. Compression is only supported for certain
234+
/// image types such as JPEG and on Android PNG and WebP, too. If compression is not supported for the image that is picked,
235+
/// a warning message will be logged.
236+
///
237+
/// The method could throw [PlatformException] if the app does not have permission to access
238+
/// the camera or photos gallery, no camera is available, plugin is already in use,
239+
/// temporary file could not be created (iOS only), plugin activity could not
240+
/// be allocated (Android only) or due to an unknown error.
241+
///
242+
/// See also [pickImage] to allow users to only pick a single image.
243+
Future<List<XFile>?> pickMultiImage({
244+
double? maxWidth,
245+
double? maxHeight,
246+
int? imageQuality,
247+
}) {
248+
return platform.getMultiImage(
249+
maxWidth: maxWidth,
250+
maxHeight: maxHeight,
251+
imageQuality: imageQuality,
252+
);
253+
}
254+
255+
/// Returns an [XFile] object wrapping the video that was picked.
256+
///
257+
/// The returned [XFile] is intended to be used within a single APP session. Do not save the file path and use it across sessions.
258+
///
259+
/// The [source] argument controls where the video comes from. This can
260+
/// be either [ImageSource.camera] or [ImageSource.gallery].
261+
///
262+
/// The [maxDuration] argument specifies the maximum duration of the captured video. If no [maxDuration] is specified,
263+
/// the maximum duration will be infinite.
264+
///
265+
/// Use `preferredCameraDevice` to specify the camera to use when the `source` is [ImageSource.camera].
266+
/// The `preferredCameraDevice` is ignored when `source` is [ImageSource.gallery]. It is also ignored if the chosen camera is not supported on the device.
267+
/// Defaults to [CameraDevice.rear].
268+
///
269+
/// In Android, the MainActivity can be destroyed for various fo reasons. If that happens, the result will be lost
270+
/// in this call. You can then call [retrieveLostData] when your app relaunches to retrieve the lost data.
271+
///
272+
/// The method could throw [PlatformException] if the app does not have permission to access
273+
/// the camera or photos gallery, no camera is available, plugin is already in use,
274+
/// temporary file could not be created and video could not be cached (iOS only),
275+
/// plugin activity could not be allocated (Android only) or due to an unknown error.
276+
///
277+
Future<XFile?> pickVideo({
278+
required ImageSource source,
279+
CameraDevice preferredCameraDevice = CameraDevice.rear,
280+
Duration? maxDuration,
281+
}) {
282+
return platform.getVideo(
283+
source: source,
284+
preferredCameraDevice: preferredCameraDevice,
285+
maxDuration: maxDuration,
286+
);
287+
}
288+
289+
/// Retrieve the lost [XFile] when [pickImage], [pickMultiImage] or [pickVideo] failed because the MainActivity
290+
/// is destroyed. (Android only)
291+
///
292+
/// Image or video can be lost if the MainActivity is destroyed. And there is no guarantee that the MainActivity is always alive.
293+
/// Call this method to retrieve the lost data and process the data according to your APP's business logic.
294+
///
295+
/// Returns a [LostDataResponse] object if successfully retrieved the lost data. The [LostDataResponse] object can \
296+
/// represent either a successful image/video selection, or a failure.
297+
///
298+
/// Calling this on a non-Android platform will throw [UnimplementedError] exception.
299+
///
300+
/// See also:
301+
/// * [LostDataResponse], for what's included in the response.
302+
/// * [Android Activity Lifecycle](https://developer.android.com/reference/android/app/Activity.html), for more information on MainActivity destruction.
303+
Future<LostDataResponse> retrieveLostData() {
304+
return platform.getLostData();
305+
}
166306
}

packages/image_picker/image_picker/pubspec.yaml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ description: Flutter plugin for selecting images from the Android and iOS image
33
library, and taking new pictures with the camera.
44
repository: https://github.com/flutter/plugins/tree/master/packages/image_picker/image_picker
55
issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+image_picker%22
6-
version: 0.8.1+4
6+
version: 0.8.2
77

88
environment:
99
sdk: ">=2.12.0 <3.0.0"
@@ -24,8 +24,8 @@ dependencies:
2424
flutter:
2525
sdk: flutter
2626
flutter_plugin_android_lifecycle: ^2.0.1
27-
image_picker_for_web: ^2.0.0
28-
image_picker_platform_interface: ^2.1.0
27+
image_picker_for_web: ^2.1.0
28+
image_picker_platform_interface: ^2.2.0
2929

3030
dev_dependencies:
3131
flutter_test:

0 commit comments

Comments
 (0)