Flutter文件打开功能插件open_file_plugin的使用
Flutter文件打开功能插件open_file_plugin的使用
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
更多关于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)
方法来打开该文件。
注意事项
- iOS权限:在iOS上,通常不需要额外的权限来访问应用沙盒内的文件。但是,如果你需要访问其他位置的文件,你可能需要在
Info.plist
中添加相应的权限声明。 - 文件类型:确保文件类型与设备上安装的应用程序兼容。如果尝试打开一个不兼容的文件类型,设备可能会提示没有可用的应用程序来打开该文件。
希望这个示例对你有所帮助!