[译]Flutter图片(视频)选取组件image_picker

2,841 阅读3分钟

「这是我参与11月更文挑战的第17天,活动详情查看:2021最后一次更文挑战」。

Flutter应用中要选择图片或视频的话,可以使用图片选取组件 image_picker 。
内容肉翻自 image_picker 的 pub 。


image_picker | Flutter Package (pub.dev)

image_picker 是用在 iOS 和 Android 两个平台上的 Flutter 图片选取组件。 该组件可从图片库中选择图片或者用相机拍新的照片。

安装

首先,在 pubspec.yaml 中添加 image_picker 的依赖。

dependencies:
  image_picker: ^0.8.4+4

iOS

该插件需要 iOS 9.0 或更高版本。

该插件从 0.8.1 版本开始,在 iOS 14 或更高版本上的实现是使用 PHPicker 选择(多选)图片。 用 PHPicker 实现会导致无法在 iOS14 或更高版本的虚拟机上选择 HEIC 图片。 这是一个已知的问题。请在真机上测试这个问题,或直到 Apple 修复这个问题前使用非 HEIC 格式的图片。

63426347 - Apple known issue

该链接为 google 搜索链接。

Info.plist 中添加以下的 key, Info.plist 位于 <project>/ios/Runner/Info.plist :

  • NSPhotoLibraryUsageDescription : 描述 APP 需要访问图片库权限的理由。在可视化编辑器中是 Privacy - Photo Library Usage Description

  • NSCameraUsageDescription : 描述 APP 需要访问相机权限的理由。在可视化编辑器中是 Privacy - Camera Usage Description

  • NSMicrophoneUsageDescription : 描述APP 需要访问麦克风权限的理由(如果想要记录视频的话)。在可视化编辑器中是 Privacy - Microphone Usage Description

Android

0.8.1 版本开始,在 Android 4.3 或更高版本的实现支持选择(多选)图片。

无需配置 - 开箱即用。

不再需要向 AndroidManifest.xml 的 标签中添加 android:requestLegacyExternalStorage="true" 属性, 这是因为 image_picker 已经更新为使用分区存储。

分区存储:Android 11 中的存储机制更新  |  Android 开发者  |  Android Developers (google.cn)

注: 使用相机捕捉的的图片和视频会保存到应用的本地缓存,因此应该只作临时使用。如果想要永久存储捕捉的图片,需要负责转移到一个更持久化的位置。

示例

import 'package:image_picker/image_picker.dart';

    ...
    final ImagePicker _picker = ImagePicker();
    // 选择图片
    final XFile? image = await _picker.pickImage(source: ImageSource.gallery);
    // 拍照
    final XFile? photo = await _picker.pickImage(source: ImageSource.camera);
    // 选择视频
    final XFile? image = await _picker.pickVideo(source: ImageSource.gallery);
    // 录像
    final XFile? video = await _picker.pickVideo(source: ImageSource.camera);
    // 选择多张图片
    final List<XFile>? images = await _picker.pickMultiImage();
    ...

处理 Android 平台的 MainActivity 销毁

Android 系统有时(即使几乎从不存在这种情况)会在 image_picker 选取完时杀死 MainActivity 。 如果发生这种情况,用 image_picker 选取的数据会丢失。 这种情况,需要使用 retrieveLostData 来找回丢失的数据。

Future<void> getLostData() async {
  final LostDataResponse response =
      await picker.retrieveLostData();
  if (response.isEmpty) {
    return;
  }
  if (response.files != null) {
    for(final XFile file in response.files) {
      _handleFile(file);
    }
  } else {
    _handleError(response.exception);
  }
}

没有方法能检测到 MainActivity 的销毁何时发生,所以在正确的位置调用这个方法是必要的。建议在一些启动检查中来处理。参考示例 APP 来确认如何使用。

迁移到 0.8.2+

image_picker 插件从 0.8.2 版本开始,添加了一些新方法。这些方法返回 XFile (来自cross_file包) 实例,而不是插件自身的 PickedFile 实例。虽然旧方法仍然存在,仍然建议你启动到对应新版本的迁移。到最后,```PickedFile`` 和返回该类型实例的方法会被标记为过时然后移除。

调用新方法

旧 API新 API
PickedFile image = await _picker.getImage(...)XFile image = await _picker.pickImage(...)
List<PickedFile> images = await _picker.getMultiImage(...)List<XFile> images = await _picker.pickMultiImage(...)
PickedFile video = await _picker.getVideo(...)XFile video = await _picker.pickVideo(...)
LostData response = await _picker.getLostData()LostDataResponse response = await _picker.retrieveLostData()