Flutter URI转换文件插件uri_to_file的使用

Flutter URI转换文件插件uri_to_file的使用

uri_to_file

Pub

uri_to_file 是一个Flutter插件,用于将支持的URI转换为文件。它支持Android和iOS平台。

支持的Uri Schema

  • content://(仅限Android)
  • File.fromUri(uri) 支持的Schema

开始使用

添加依赖

在项目的pubspec.yaml文件中添加以下依赖:

dependencies:
  uri_to_file: ^1.0.0

使用方法

下面是一个简单的示例,演示如何将URI转换为文件:

import 'dart:io';

import 'package:uri_to_file/uri_to_file.dart';

Future<void> convertUriToFile() async {
  try {
    String uriString = 'content://sample.txt'; // Uri string

    // 不要通过 uri.toString() 传递 Uri 对象作为参数。
    // 因为 uri.toString() 会将字符串转换为小写,这会导致此包行为异常

    // 如果你正在使用 uni_links 包进行深度链接。
    // 请使用 getInitialLink() 或 linkStream 传递 Uri 字符串

    File file = await toFile(uriString); // 将 uri 转换为文件
    print('文件路径:${file.path}');
  } catch (e) {
    print(e); // 异常
  }
}

重要提示

  • 不要通过 uri.toString() 传递 Uri 对象作为参数。因为 uri.toString() 会将字符串转换为小写,这会导致此包行为异常。
  • 如果你正在使用 uni_links 包进行深度链接,请使用 getInitialLink()linkStream 传递 Uri 字符串。
  • 查看完整示例:https://pub.dev/packages/uri_to_file/example

完整示例demo

下面是一个完整的示例应用程序,展示了如何处理从其他应用打开的文件并将其URI转换为文件。

import 'dart:io';
import 'package:flutter/material.dart';
import 'package:fluttertoast/fluttertoast.dart';
import 'package:path/path.dart';
import 'package:uri_to_file/uri_to_file.dart';
import 'package:uni_links/uni_links.dart';

Future<void> main() async {
  WidgetsFlutterBinding.ensureInitialized();
  await clearTemporaryFiles();
  runApp(const MyApp());
}

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

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

class _MyAppState extends State<MyApp> {
  bool _isLoading = false, _hasError = false;
  File? _file;

  @override
  void initState() {
    init();
    super.initState();
  }

  /// 初始化
  void init() {
    _processInitialUri();
    _listenForUri();
  }

  /// 获取初始 Uri
  Future<void> _processInitialUri() async {
    String? uriString = await getInitialLink();
    _processUri(uriString);
  }

  /// 监听 Uri
  void _listenForUri() {
    linkStream.listen((uriString) => _processUri(uriString));
  }

  /// 处理 Uri
  Future<void> _processUri(String? uriString) async {
    try {
      if (uriString != null) {
        _hasError = false;
        _isLoading = true;
        setState(() {});
        _file = await toFile(uriString);
        _isLoading = false;
        setState(() {});
      }
    } catch (e) {
      Fluttertoast.showToast(msg: 'Something went wrong. Please try again');
      _hasError = true;
      print(e.toString());
    }
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: const Text('Uri To File Example'),
        ),
        body: Container(
          padding: const EdgeInsets.all(16.0),
          child: _body(),
        ),
      ),
    );
  }

  Widget _body() {
    return Column(
      mainAxisSize: MainAxisSize.max,
      mainAxisAlignment: MainAxisAlignment.start,
      crossAxisAlignment: CrossAxisAlignment.start,
      children: [
        _getStepsInfo(),
        _getFileDetails(),
      ],
    );
  }

  Widget _getStepsInfo() {
    return const Column(
      mainAxisSize: MainAxisSize.min,
      mainAxisAlignment: MainAxisAlignment.start,
      crossAxisAlignment: CrossAxisAlignment.start,
      children: [
        Text(
          'Note:',
          overflow: TextOverflow.ellipsis,
          style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
        ),
        Row(
          mainAxisSize: MainAxisSize.max,
          mainAxisAlignment: MainAxisAlignment.start,
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            Text(
              '-',
              style: TextStyle(fontSize: 14, fontWeight: FontWeight.w600),
            ),
            Expanded(
              child: Text(
                'Open any file from file browser app or any other app and select uri_to_file_example app.',
                style: TextStyle(fontSize: 14, fontWeight: FontWeight.w600),
              ),
            ),
          ],
        ),
        Row(
          mainAxisSize: MainAxisSize.max,
          mainAxisAlignment: MainAxisAlignment.start,
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            Text(
              '-',
              style: TextStyle(fontSize: 14, fontWeight: FontWeight.w600),
            ),
            Expanded(
              child: Text(
                'File opened from file browser app or any other app.\nIt contains content:// uri.',
                style: TextStyle(fontSize: 14, fontWeight: FontWeight.w600),
              ),
            ),
          ],
        ),
      ],
    );
  }

  Widget _getFileDetails() {
    return Expanded(
      child: Column(
        mainAxisSize: MainAxisSize.max,
        mainAxisAlignment: MainAxisAlignment.center,
        crossAxisAlignment: CrossAxisAlignment.center,
        children: [
          const Row(
            children: [
              Expanded(
                child: Text(
                  'Opened',
                  textAlign: TextAlign.center,
                  overflow: TextOverflow.ellipsis,
                  style: TextStyle(fontSize: 18, fontWeight: FontWeight.w600),
                ),
              ),
            ],
          ),
          const Row(
            children: [
              Expanded(
                child: Text(
                  'File Name',
                  textAlign: TextAlign.center,
                  overflow: TextOverflow.ellipsis,
                  style: TextStyle(fontSize: 18, fontWeight: FontWeight.w600),
                ),
              ),
            ],
          ),
          _getFileName(),
        ],
      ),
    );
  }

  Widget _getFileName() {
    if (_isLoading) {
      return Container(
        margin: const EdgeInsets.only(top: 8.0),
        child: const SizedBox(
          width: 16.0,
          height: 16.0,
          child: CircularProgressIndicator(
            strokeWidth: 3.0,
          ),
        ),
      );
    }

    if (_file != null) {
      return Row(
        children: [
          Expanded(
            child: Text(
              basename(_file!.path),
              textAlign: TextAlign.center,
              overflow: TextOverflow.ellipsis,
              style: const TextStyle(fontSize: 16, fontWeight: FontWeight.w600),
            ),
          ),
        ],
      );
    }

    return Row(
      children: [
        Expanded(
          child: Text(
            (_hasError) ? 'Error' : 'N/A',
            textAlign: TextAlign.center,
            overflow: TextOverflow.ellipsis,
            style: const TextStyle(fontSize: 16, fontWeight: FontWeight.w600),
          ),
        ),
      ],
    );
  }
}

工作原理

  • content:// (仅限Android)
    uri_to_file 使用原生通道创建一个临时文件,并将其存储在应用程序目录中。
  • 其他 URI
    其他 URI 由 Flutter SDK 自身通过 File.fromUri(uri) 处理。

许可证

MIT License

功能和Bug

请在 GitHub Issues 中提交功能请求和Bug报告。


希望这个详细的说明和示例代码能帮助你更好地理解和使用 uri_to_file 插件!如果有任何问题或需要进一步的帮助,请随时提问。


更多关于Flutter URI转换文件插件uri_to_file的使用的实战教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter URI转换文件插件uri_to_file的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


当然,下面是一个关于如何在Flutter项目中使用uri_to_file插件的示例代码。这个插件可以将URI转换为文件路径,非常适用于处理从其他应用接收到的内容URI(如从文件选择器获取的文件)。

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

dependencies:
  flutter:
    sdk: flutter
  uri_to_file: ^x.y.z  # 请替换为最新版本号

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

接下来,你可以在你的Flutter应用中这样使用uri_to_file插件:

import 'package:flutter/material.dart';
import 'package:uri_to_file/uri_to_file.dart';
import 'package:path_provider/path_provider.dart';

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: Text('URI to File Example'),
        ),
        body: UriToFileExample(),
      ),
    );
  }
}

class UriToFileExample extends StatefulWidget {
  @override
  _UriToFileExampleState createState() => _UriToFileExampleState();
}

class _UriToFileExampleState extends State<UriToFileExample> {
  String? filePath;

  @override
  Widget build(BuildContext context) {
    return Center(
      child: Column(
        mainAxisAlignment: MainAxisAlignment.center,
        children: <Widget>[
          Text('Converted File Path:'),
          Text(filePath ?? 'N/A', style: TextStyle(fontSize: 18)),
          SizedBox(height: 20),
          ElevatedButton(
            onPressed: _pickFileAndConvertUri,
            child: Text('Pick File and Convert URI'),
          ),
        ],
      ),
    );
  }

  Future<void> _pickFileAndConvertUri() async {
    // Here you would typically use a file picker plugin to get a URI.
    // For simplicity, let's assume we have a sample URI.
    // In reality, you would replace this URI with the one obtained from the file picker.
    String sampleUri = "content://com.example.provider/external_files/sample.txt";

    try {
      // Convert URI to file path
      File file = await UriToFile.convertToFilePath(Uri.parse(sampleUri));
      setState(() {
        filePath = file.path;
      });
    } catch (e) {
      print("Error converting URI to file path: $e");
      // Handle the error appropriately
    }
  }
}

注意

  1. 上述代码假设你已经有一个内容URI(例如从文件选择器获取的URI)。在真实应用中,你需要使用文件选择器插件(如file_picker)来获取用户选择的文件的URI。
  2. 由于Android的权限和文件访问限制,某些URI可能需要额外的权限或内容访问提供者才能成功转换为文件路径。
  3. 如果你的应用需要处理敏感或私有文件,请确保遵循最佳实践和Android/iOS的安全指导。

文件选择器插件示例(如果需要): 你可以使用file_picker插件来获取文件URI,如下所示:

dependencies:
  file_picker: ^x.y.z  # 请替换为最新版本号

然后在你的代码中使用file_picker来选择文件并获取URI:

import 'package:file_picker/file_picker.dart';

// 在你的_UriToFileExampleState类中
Future<void> _pickFile() async {
  FilePickerResult? result = await FilePicker.platform.pickFiles();

  if (result != null && result.files.isNotEmpty) {
    FilePickerFile file = result.files.first;
    // 获取文件URI
    String fileUri = file.path;  // 在Android上这是URI,在iOS上这是文件路径

    // 根据平台不同处理URI或路径
    if (Platform.isAndroid) {
      // 对于Android,file.path是一个内容URI
      try {
        File convertedFile = await UriToFile.convertToFilePath(Uri.parse(fileUri));
        setState(() {
          filePath = convertedFile.path;
        });
      } catch (e) {
        print("Error converting URI to file path: $e");
      }
    } else if (Platform.isIOS) {
      // 对于iOS,file.path已经是一个文件路径
      setState(() {
        filePath = fileUri;
      });
    }
  }
}

确保根据文件选择器返回的URI类型进行适当的处理。

回到顶部