Flutter内容访问插件content_resolver的使用

Flutter内容访问插件 content_resolver 的使用

content_resolver 插件用于解析 Android 中常用的 Content Providers 所使用的 content: URI。下面将详细介绍如何安装和使用这个插件,并提供一个完整的示例代码。

安装

在你的 pubspec.yaml 文件中添加以下依赖并执行 flutter pub get

dependencies:
  content_resolver: ^0.3.2

使用

解析内容

下面是一个使用 app_links 插件来接收 content: URI 内容的片段示例:

import 'package:app_links/app_links.dart';
import 'package:content_resolver/content_resolver.dart';

final _appLinks = AppLinks(onAppLink: (uri) async {
  // 如果数据是一些图片,你可以直接将数据传递给 Image.data 或其他组件。
  final Content content = await ContentResolver.resolveContent(uri);
  // 处理接收到的内容
});

写入内容

下面是一个向 content: URI 写入数据的片段示例:

import 'dart:typed_data';
import 'package:content_resolver/content_resolver.dart';

final data = Uint8List.fromList(utf8.encode('Hello World'));
await ContentResolver.writeContent(uri.toString(), data);
// 注意:如果 URI 不可写,则会抛出异常。

完整示例 Demo

以下是一个完整的示例代码,展示了如何处理通过 content: URI 接收的内容,并将其保存到本地存储中:

import 'dart:async';
import 'dart:io';
import 'dart:typed_data';
import 'package:app_links/app_links.dart';
import 'package:content_resolver/content_resolver.dart';
import 'package:flutter/material.dart';
import 'package:path_provider/path_provider.dart';
import 'package:rxdart/rxdart.dart';

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

class MyApp extends StatefulWidget {
  @override
  _MyAppState createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  final _contentSubject = PublishSubject<Content>();
  late final StreamSubscription<String> _appLinksSub;

  @override
  void initState() {
    super.initState();
    // 示例说明了如何使用 ContentResolver 处理内容意图。
    _appLinksSub = AppLinks().stringLinkStream.listen(_handleUri);
    Future.microtask(() async {
      _handleUri(await AppLinks().getInitialLinkString());
    });
  }

  Future<void> _handleUri(String? uri) async {
    if (uri == null) return;
    final metadata = await ContentResolver.resolveContentMetadata(uri);
    final bb = BytesBuilder();
    ContentResolver.resolveContentToStream(uri).listen((event) {
      bb.add(event);
    }, onDone: () {
      _save(bb.toBytes());
      _contentSubject.add(
        Content(
          data: bb.toBytes(),
          mimeType: metadata.mimeType,
          fileName: metadata.fileName,
        ),
      );
    });
  }

  Future<void> _save(Uint8List data) async {
    final dir = await getExternalStorageDirectory();
    await dir!.create(recursive: true);
    await File('${dir.path}/test.jpg').writeAsBytes(data);
  }

  @override
  void dispose() {
    _appLinksSub.cancel();
    _contentSubject.close();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: const Text('ContentResolver example app'),
        ),
        body: StreamBuilder<Content>(
            stream: _contentSubject.stream,
            builder: (context, snapshot) {
              return Center(
                child: snapshot.hasData
                    ? Image.memory(snapshot.data!.data)
                    : Text('Nothing received.'),
              );
            }),
      ),
    );
  }
}

class Content {
  final Uint8List data;
  final String mimeType;
  final String fileName;

  Content({required this.data, required this.mimeType, required this.fileName});
}

此示例展示了如何监听应用链接中的 content: URI,解析内容并将其保存到设备的外部存储中。最后,它会在屏幕上显示接收到的图像。请确保你已经添加了必要的权限(如读取和写入外部存储)到你的 AndroidManifest.xml 文件中。


更多关于Flutter内容访问插件content_resolver的使用的实战教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

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


在Flutter中,如果你想访问Android设备上的内容(如文件、图片等),通常会使用到content_resolver相关的功能。尽管Flutter本身没有直接名为content_resolver的插件,但你可以通过platform_channels与原生Android代码进行交互,从而实现访问内容的功能。

下面是一个简单的示例,展示如何在Flutter中通过Platform Channels调用Android的ContentResolver来访问设备上的图片。

1. 创建Flutter项目

首先,确保你已经安装了Flutter SDK,并创建了一个新的Flutter项目。

flutter create content_resolver_example
cd content_resolver_example

2. 在Android原生代码中实现ContentResolver功能

编辑android/app/src/main/kotlin/.../MainActivity.kt(如果你使用的是Kotlin)或android/app/src/main/java/.../MainActivity.java(如果你使用的是Java)。

Kotlin示例

package com.example.content_resolver_example

import android.content.ContentResolver
import android.content.ContentUris
import android.content.Context
import android.database.Cursor
import android.net.Uri
import android.provider.MediaStore
import androidx.annotation.NonNull
import io.flutter.embedding.android.FlutterActivity
import io.flutter.embedding.engine.FlutterEngine
import io.flutter.plugin.common.MethodChannel

class MainActivity: FlutterActivity() {
    private val CHANNEL = "com.example.content_resolver_example/channel"

    override fun configureFlutterEngine(@NonNull flutterEngine: FlutterEngine) {
        super.configureFlutterEngine(flutterEngine)
        MethodChannel(flutterEngine.dartExecutor.binaryMessenger, CHANNEL).setMethodCallHandler { call, result ->
            if (call.method == "getImages") {
                val images = getImageUris(this)
                result.success(images)
            } else {
                result.notImplemented()
            }
        }
    }

    private fun getImageUris(context: Context): List<String> {
        val projection = arrayOf(MediaStore.Images.Media._ID)
        val selection = "${MediaStore.Images.Media.MIME_TYPE} = ? OR ${MediaStore.Images.Media.MIME_TYPE} = ?"
        val selectionArgs = arrayOf("image/jpeg", "image/png")

        val sortOrder = "${MediaStore.Images.Media._ID} DESC"

        val resolver = context.contentResolver
        val uri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI
        val cursor: Cursor? = resolver.query(
            uri, projection, selection, selectionArgs, sortOrder
        )

        val imageUris = mutableListOf<String>()
        cursor?.use {
            if (it.moveToFirst()) {
                do {
                    val id = it.getLong(it.getColumnIndexOrThrow(MediaStore.Images.Media._ID))
                    val contentUri = ContentUris.withAppendedId(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, id)
                    imageUris.add(contentUri.toString())
                } while (it.moveToNext())
            }
        }

        return imageUris
    }
}

3. 在Flutter中调用原生方法

编辑lib/main.dart文件,添加一个按钮来调用原生方法并显示结果。

import 'package:flutter/material.dart';
import 'package:flutter/services.dart';

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

class MyApp extends StatelessWidget {
  static const platform = const MethodChannel('com.example.content_resolver_example/channel');

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: const Text('Content Resolver Example'),
        ),
        body: Center(
          child: ElevatedButton(
            onPressed: _getImages,
            child: Text('Get Images'),
          ),
        ),
      ),
    );
  }

  Future<void> _getImages() async {
    try {
      final String result = await platform.invokeMethod('getImages');

      // 假设返回的是JSON数组格式的字符串,需要转换成List<String>
      final List<dynamic> imageUris = jsonDecode(result);
      print('Image URIs: $imageUris');

      // 你可以在这里显示图片,比如使用Image.network(uri)
    } on PlatformException catch (e) {
      print("Failed to invoke: '${e.message}'.");
    }
  }
}

4. 运行应用

确保你已经连接了一个Android设备或启动了Android模拟器,然后运行Flutter应用。

flutter run

点击按钮后,你应该能在控制台看到从设备中检索到的图片URI列表。你可以进一步处理这些URI,例如在Flutter应用中显示这些图片。

这个示例展示了如何通过Platform Channels在Flutter中调用Android的ContentResolver。你可以根据需要扩展这个示例,以实现更复杂的功能。

回到顶部