Flutter文件打开功能插件open_file_plugin的使用

发布于 1周前 作者 wuwangju 来自 Flutter

Flutter文件打开功能插件open_file_plugin的使用

pub package

open_file_plugin 是一个在 Flutter 中调用原生应用来打开文件的插件,支持 iOS(DocumentInteraction)、Android(intent)、PC(ffi)和 Web(dart:html)。

这个包是从 这里 分支而来,用于处理 .apk 文件,并修复了某些情况下底部弹出框无法打开的问题,特别是在三星 Android 13 设备上。

使用方法

要使用此插件,将 open_file_plugin 添加为您的 pubspec.yaml 文件中的依赖项:

dependencies:
  open_file_plugin: ^lastVersion

示例代码

以下是一个完整的示例,展示了如何使用 open_file_plugin 打开文件。

import 'dart:io';

import 'package:flutter/material.dart';
import 'dart:async';
import 'package:open_file_plugin/open_file_plugin.dart';
import 'package:file_picker/file_picker.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatefulWidget {
  const MyApp({super.key});

  @override
  State<MyApp> createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  var _openResult = 'Unknown';
  String? filePath = '/storage/emulated/0/Download/Link File Share/3.pdf';
  String message = "Please pick file";

  Future<void> openFile() async {
    if (filePath != null) {
      final result = await OpenFile.open(filePath!, isAskForAllFileAccess: true);
      setState(() {
        _openResult = "type=${result.type}  message=${result.message}";
      });
    }
  }

  Future<void> pickFile() async {
    FilePickerResult? result = await FilePicker.platform.pickFiles();

    if (result != null) {
      setState(() {
        filePath = result.paths.first;
      });
    } else {
      // 用户取消了选择文件
    }
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: const Text('Plugin example app'),
        ),
        body: Center(
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: <Widget>[
              Row(
                mainAxisAlignment: Platform.isAndroid
                    ? MainAxisAlignment.spaceAround
                    : MainAxisAlignment.center,
                children: [
                  Platform.isAndroid
                      ? ElevatedButton(
                          onPressed: () async {
                            filePath = await OpenFile.pickRandomFile();
                            setState(
                              () {},
                            );
                          },
                          child: const Text('Pick Simple File'),
                        )
                      : const SizedBox(),
                  ElevatedButton(
                    onPressed: pickFile,
                    child: const Text('Pick Media File'),
                  ),
                ],
              ),
              Text(
                  '\n${filePath == null ? message : "File Path => $filePath"}\n'),
              ElevatedButton(
                onPressed: openFile,
                child: const Text('Open File'),
              ),
              Text('\nopen result: $_openResult\n'),
            ],
          ),
        ),
      ),
    );
  }
}

支持的文件类型

Android

{
    ".3gp":    "video/3gpp",
    ".torrent":"application/x-bittorrent",
    ".kml":    "application/vnd.google-earth.kml+xml",
    ".gpx":    "application/gpx+xml",
    ".csv":    "application/vnd.ms-excel",
    ".apk":    "application/vnd.android.package-archive",
    ".asf":    "video/x-ms-asf",
    ".avi":    "video/x-msvideo",
    ".bin":    "application/octet-stream",
    ".bmp":    "image/bmp",
    ".c":      "text/plain",
    ".class":  "application/octet-stream",
    ".conf":   "text/plain",
    ".cpp":    "text/plain",
    ".doc":    "application/msword",
    ".docx":   "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
    ".xls":    "application/vnd.ms-excel",
    ".xlsx":   "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
    ".exe":    "application/octet-stream",
    ".gif":    "image/gif",
    ".gtar":   "application/x-gtar",
    ".gz":     "application/x-gzip",
    ".h":      "text/plain",
    ".htm":    "text/html",
    ".html":   "text/html",
    ".jar":    "application/java-archive",
    ".java":   "text/plain",
    ".jpeg":   "image/jpeg",
    ".jpg":    "image/jpeg",
    ".js":     "application/x-javascript",
    ".log":    "text/plain",
    ".m3u":    "audio/x-mpegurl",
    ".m4a":    "audio/mp4a-latm",
    ".m4b":    "audio/mp4a-latm",
    ".m4p":    "audio/mp4a-latm",
    ".m4u":    "video/vnd.mpegurl",
    ".m4v":    "video/x-m4v",
    ".mov":    "video/quicktime",
    ".mp2":    "audio/x-mpeg",
    ".mp3":    "audio/x-mpeg",
    ".mp4":    "video/mp4",
    ".mpc":    "application/vnd.mpohun.certificate",
    ".mpe":    "video/mpeg",
    ".mpeg":   "video/mpeg",
    ".mpg":    "video/mpeg",
    ".mpg4":   "video/mp4",
    ".mpga":   "audio/mpeg",
    ".msg":    "application/vnd.ms-outlook",
    ".ogg":    "audio/ogg",
    ".pdf":    "application/pdf",
    ".png":    "image/png",
    ".pps":    "application/vnd.ms-powerpoint",
    ".ppt":    "application/vnd.ms-powerpoint",
    ".pptx":   "application/vnd.openxmlformats-officedocument.presentationml.presentation",
    ".prop":   "text/plain",
    ".rc":     "text/plain",
    ".rmvb":   "audio/x-pn-realaudio",
    ".rtf":    "application/rtf",
    ".sh":     "text/plain",
    ".tar":    "application/x-tar",
    ".tgz":    "application/x-compressed",
    ".txt":    "text/plain",
    ".wav":    "audio/x-wav",
    ".wma":    "audio/x-ms-wma",
    ".wmv":    "audio/x-ms-wmv",
    ".wps":    "application/vnd.ms-works",
    ".xml":    "text/plain",
    ".z":      "application/x-compress",
    ".zip":    "application/x-zip-compressed",
    "":        "*/*"
}

你需要指定额外的权限以打开相应的文件类型。例如:

媒体类型 请求的权限 Android版本
APK文件 android.permission.REQUEST_INSTALL_PACKAGES -
所有文件 android.permission.MANAGE_EXTERNAL_STORAGE 12+
图片和照片 android.permission.READ_MEDIA_IMAGES 13+
视频 android.permission.READ_MEDIA_VIDEO 13+
音频文件 android.permission.READ_MEDIA_AUDIO 13+

如果与其他插件冲突导致 FileProvider 错误,可以在 /android/app/src/main/AndroidManifest.xml 中添加以下代码:

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
          xmlns:tools="http://schemas.android.com/tools" package="xxx.xxx.xxxxx">
    <application>
        ...
        <provider android:name="androidx.core.content.FileProvider"
                  android:authorities="${applicationId}.fileProvider"
                  android:exported="false"
                  android:grantUriPermissions="true"
                  tools:replace="android:authorities">
            <meta-data android:name="android.support.FILE_PROVIDER_PATHS"
                       android:resource="@xml/filepaths"
                       tools:replace="android:resource" />
        </provider>
    </application>
</manifest>

如果遇到 Android 依赖 'com.android.support:appcompat-v7' 版本不一致导致的编译错误,可以在 /android/build.gradle 中添加以下代码:

subprojects {
    project.configurations.all {
        resolutionStrategy.eachDependency { details ->
            if (details.requested.group == 'com.android.support'
                    && !details.requested.name.contains('multidex') ) {
                details.useVersion "27.1.1"
            }
        }
    }
}

iOS

对于 iOS,你可以使用 UTI(统一类型标识符)来处理不同的文件类型。

{
    ".rtf":    "public.rtf",
    ".txt":    "public.plain-text",
    ".html":   "public.html",
    ".htm":    "public.html",
    ".xml":    "public.xml",
    ".tar":    "public.tar-archive",
    ".gz":     "org.gnu.gnu-zip-archive",
    ".gzip":   "org.gnu.gnu-zip-archive",
    ".tgz":    "org.gnu.gnu-zip-tar-archive",
    ".jpg":    "public.jpeg",
    ".jpeg":   "public.jpeg",
    ".png":    "public.png",
    ".avi":    "public.avi",
    ".mpg":    "public.mpeg",
    ".mpeg":   "public.mpeg",
    ".mp4":    "public.mpeg-4",
    ".3gpp":   "public.3gpp",
    ".3gp":    "public.3gpp",
    ".mp3":    "public.mp3",
    ".zip":    "com.pkware.zip-archive",
    ".gif":    "com.compuserve.gif",
    ".bmp":    "com.microsoft.bmp",
    ".ico":    "com.microsoft.ico",
    ".doc":    "com.microsoft.word.doc",
    ".xls":    "com.microsoft.excel.xls",
    ".ppt":    "com.microsoft.powerpoint.ppt",
    ".wav":    "com.microsoft.waveform-audio",
    ".wm":     "com.microsoft.windows-media-wm",
    ".wmv":    "com.microsoft.windows-media-wmv",
    ".pdf":    "com.adobe.pdf"
}

更多关于Flutter文件打开功能插件open_file_plugin的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter文件打开功能插件open_file_plugin的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


当然,以下是如何在Flutter项目中使用open_file插件来实现文件打开功能的示例代码。需要注意的是,open_file_plugin已经更名为open_file,所以我们将使用open_file插件。

1. 添加依赖

首先,在你的pubspec.yaml文件中添加open_file依赖:

dependencies:
  flutter:
    sdk: flutter
  open_file: ^3.2.1  # 请检查最新版本号

然后运行flutter pub get来安装依赖。

2. 请求权限(Android)

在Android上打开文件通常需要请求存储权限。你需要在android/app/src/main/AndroidManifest.xml文件中添加以下权限:

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.yourapp">

    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>

    <!-- 其他配置 -->

</manifest>

由于Android 10(API级别29)及以上版本对存储权限有更严格的限制,你可能需要使用storage_permissions插件或其他方法来请求运行时权限。以下是一个简单的示例,展示如何请求权限(需要额外安装permission_handler插件):

dependencies:
  permission_handler: ^10.2.0  # 请检查最新版本号

然后在你的Dart代码中请求权限:

import 'package:permission_handler/permission_handler.dart';

Future<void> requestPermissions() async {
  var status = await Permission.storage.status;
  if (!status.isGranted) {
    var result = await Permission.storage.request();
    if (!result.isGranted) {
      // 权限被拒绝
      throw Exception('存储权限被拒绝');
    }
  }
}

3. 使用open_file插件打开文件

下面是一个完整的示例,展示如何使用open_file插件打开文件:

import 'package:flutter/material.dart';
import 'package:open_file/open_file.dart';
import 'package:path_provider/path_provider.dart';
import 'dart:io';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: Text('文件打开示例'),
        ),
        body: Center(
          child: ElevatedButton(
            onPressed: _openFile,
            child: Text('打开文件'),
          ),
        ),
      ),
    );
  }

  Future<void> _openFile() async {
    try {
      // 请求存储权限(如果需要)
      await requestPermissions();

      // 获取应用文档目录
      Directory appDocDir = await getApplicationDocumentsDirectory();
      String filePath = '${appDocDir.path}/example.txt';

      // 创建一个示例文件(如果不存在)
      File file = File(filePath);
      if (!await file.exists()) {
        await file.create(recursive: true);
        await file.writeAsString('这是一个示例文件内容');
      }

      // 打开文件
      await OpenFile.open(filePath);
    } catch (e) {
      print('打开文件失败: $e');
    }
  }
}

在这个示例中,我们首先请求存储权限(如果需要),然后获取应用文档目录,并创建一个示例文本文件。最后,我们使用OpenFile.open(filePath)方法来打开该文件。

注意事项

  1. iOS权限:在iOS上,通常不需要额外的权限来访问应用沙盒内的文件。但是,如果你需要访问其他位置的文件,你可能需要在Info.plist中添加相应的权限声明。
  2. 文件类型:确保文件类型与设备上安装的应用程序兼容。如果尝试打开一个不兼容的文件类型,设备可能会提示没有可用的应用程序来打开该文件。

希望这个示例对你有所帮助!

回到顶部