You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

如何实现Flutter应用接收其他App的Intent(分享文件场景)

实现Flutter应用接收其他App发送的Intent(含图片分享场景)

我来帮你解决这个问题——让Flutter应用接收其他App分享的Intent(比如从相册分享图片)其实需要分Android端配置iOS端配置Flutter端逻辑处理三部分,下面一步步给你讲清楚:

一、快速方案:使用第三方插件(推荐)

最省心的方式是用成熟的第三方插件,比如receive_sharing_intent,它已经封装了跨平台的Intent/分享接收逻辑。

1. 安装插件

pubspec.yaml中添加依赖:

dependencies:
  receive_sharing_intent: ^latest_version

然后运行flutter pub get拉取依赖。

2. Flutter端监听分享数据

在你的主页面中,初始化监听并处理接收的图片:

import 'package:receive_sharing_intent/receive_sharing_intent.dart';
import 'package:http/http.dart' as http;
import 'dart:io';

class MyHomePage extends StatefulWidget {
  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  Stream<List<SharedMediaFile>>? _sharedFilesStream;
  List<SharedMediaFile> _sharedFiles = [];

  @override
  void initState() {
    super.initState();
    // 监听实时分享的内容(App前台时)
    _sharedFilesStream = ReceiveSharingIntent.getMediaStream();
    _sharedFilesStream?.listen((List<SharedMediaFile> files) {
      setState(() {
        _sharedFiles = files;
      });
      // 拿到图片后触发上传
      if (_sharedFiles.isNotEmpty) {
        uploadImage(File(_sharedFiles.first.path));
      }
    });

    // 处理应用启动时已存在的分享数据(比如分享时App未打开)
    ReceiveSharingIntent.getInitialMedia().then((List<SharedMediaFile> files) {
      setState(() {
        _sharedFiles = files;
      });
      if (_sharedFiles.isNotEmpty) {
        uploadImage(File(_sharedFiles.first.path));
      }
    });
  }

  // 图片上传的HTTP请求实现
  Future<void> uploadImage(File imageFile) async {
    var request = http.MultipartRequest(
      'POST',
      Uri.parse('https://your-upload-api-url.com/upload'),
    );
    request.files.add(await http.MultipartFile.fromPath('image', imageFile.path));
    var response = await request.send();
    if (response.statusCode == 200) {
      print('图片上传成功');
    } else {
      print('图片上传失败:${response.statusCode}');
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('接收分享示例')),
      body: _sharedFiles.isEmpty
          ? const Text('等待其他App分享图片...')
          : Image.file(File(_sharedFiles.first.path)),
    );
  }
}

3. 平台端补充配置

  • Android:插件会自动添加基础的intent-filter,如果需要限定只接收图片,可以手动修改android/app/src/main/AndroidManifest.xml的Main Activity:
<activity
    android:name=".MainActivity"
    android:exported="true">
    <intent-filter>
        <action android:name="android.intent.action.MAIN"/>
        <category android:name="android.intent.category.LAUNCHER"/>
    </intent-filter>
    <!-- 接收单张图片分享 -->
    <intent-filter>
        <action android:name="android.intent.action.SEND"/>
        <category android:name="android.intent.category.DEFAULT"/>
        <data android:mimeType="image/*"/>
    </intent-filter>
    <!-- 接收多张图片分享 -->
    <intent-filter>
        <action android:name="android.intent.action.SEND_MULTIPLE"/>
        <category android:name="android.intent.category.DEFAULT"/>
        <data android:mimeType="image/*"/>
    </intent-filter>
</activity>

Android 13及以上需添加读取媒体权限:

<uses-permission android:name="android.permission.READ_MEDIA_IMAGES"/>
  • iOS:在ios/Runner/Info.plist中添加图片支持配置,让系统识别你的App可接收图片:
<key>CFBundleDocumentTypes</key>
<array>
    <dict>
        <key>CFBundleTypeName</key>
        <string>Image</string>
        <key>LSHandlerRank</key>
        <string>Alternate</string>
        <key>LSItemContentTypes</key>
        <array>
            <string>public.image</string>
        </array>
    </dict>
</array>

二、自定义实现(不依赖第三方插件)

如果你不想用第三方插件,可以通过MethodChannel实现原生与Flutter的通信,手动处理Intent/分享数据。

Android端步骤

  1. 按上面的方式在AndroidManifest.xml中添加intent-filter
  2. MainActivity.kt中获取Intent数据并传递给Flutter:
import android.content.Intent
import android.net.Uri
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.your.app/intent"

    override fun configureFlutterEngine(flutterEngine: FlutterEngine) {
        super.configureFlutterEngine(flutterEngine)
        MethodChannel(flutterEngine.dartExecutor.binaryMessenger, CHANNEL).setMethodCallHandler { call, result ->
            if (call.method == "getSharedImage") {
                val imageUri = intent?.getParcelableExtra<Uri>(Intent.EXTRA_STREAM)
                result.success(imageUri?.path)
            }
        }
    }

    override fun onNewIntent(intent: Intent) {
        super.onNewIntent(intent)
        this.intent = intent
        // 通知Flutter后台收到新分享
        MethodChannel(flutterEngine?.dartExecutor?.binaryMessenger, CHANNEL)
            .invokeMethod("onNewSharedImage", intent.getParcelableExtra<Uri>(Intent.EXTRA_STREAM)?.path)
    }
}

iOS端步骤

  1. 按上面的方式在Info.plist中添加图片支持配置。
  2. AppDelegate.swift中处理分享URL并传递给Flutter:
import UIKit
import Flutter

@UIApplicationMain
@objc class AppDelegate: FlutterAppDelegate {
    private let CHANNEL = "com.your.app/intent"

    override func application(
        _ application: UIApplication,
        didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
    ) -> Bool {
        let controller : FlutterViewController = window?.rootViewController as! FlutterViewController
        let channel = FlutterMethodChannel(name: CHANNEL, binaryMessenger: controller.binaryMessenger)
        channel.setMethodCallHandler { (call, result) in
            if call.method == "getSharedImage" {
                if let url = launchOptions?[.url] as? URL {
                    result.success(url.path)
                } else {
                    result.success(nil)
                }
            }
        }
        GeneratedPluginRegistrant.register(with: self)
        return super.application(application, didFinishLaunchingWithOptions: launchOptions)
    }

    override func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey : Any] = [:]) -> Bool {
        let controller : FlutterViewController = window?.rootViewController as! FlutterViewController
        let channel = FlutterMethodChannel(name: CHANNEL, binaryMessenger: controller.binaryMessenger)
        channel.invokeMethod("onNewSharedImage", arguments: url.path)
        return true
    }
}

Flutter端处理

通过MethodChannel监听原生传来的数据:

import 'package:flutter/services.dart';
import 'package:http/http.dart' as http;
import 'dart:io';

class MyHomePage extends StatefulWidget {
  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  static const platform = MethodChannel('com.your.app/intent');
  String? _imagePath;

  @override
  void initState() {
    super.initState();
    // 获取启动时的分享数据
    _getInitialImage();
    // 监听新的分享数据
    platform.setMethodCallHandler((call) async {
      if (call.method == "onNewSharedImage") {
        setState(() {
          _imagePath = call.arguments as String;
        });
        if (_imagePath != null) {
          uploadImage(File(_imagePath!));
        }
      }
    });
  }

  Future<void> _getInitialImage() async {
    try {
      final String? path = await platform.invokeMethod('getSharedImage');
      setState(() {
        _imagePath = path;
      });
      if (_imagePath != null) {
        uploadImage(File(_imagePath!));
      }
    } on PlatformException catch (e) {
      print("获取初始图片失败: ${e.message}");
    }
  }

  Future<void> uploadImage(File imageFile) async {
    // 和快速方案的上传逻辑一致
    var request = http.MultipartRequest(
      'POST',
      Uri.parse('https://your-upload-api-url.com/upload'),
    );
    request.files.add(await http.MultipartFile.fromPath('image', imageFile.path));
    var response = await request.send();
    if (response.statusCode == 200) {
      print('图片上传成功');
    } else {
      print('图片上传失败:${response.statusCode}');
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('自定义接收分享')),
      body: _imagePath == null
          ? const Text('等待其他App分享图片...')
          : Image.file(File(_imagePath!)),
    );
  }
}

注意事项

  • Android端:如果分享的图片在外部存储,需要动态申请读取权限(Android 13+用READ_MEDIA_IMAGES,低版本用READ_EXTERNAL_STORAGE)。
  • iOS端:若需访问照片库,需在Info.plist中添加隐私声明:
<key>NSPhotoLibraryUsageDescription</key>
<string>需要访问照片库以接收分享的图片</string>
  • 测试时,打开系统相册选一张图片点击分享,找到你的Flutter应用就能触发流程啦!

内容的提问来源于stack exchange,提问作者noam aghai

火山引擎 最新活动