You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在iOS分享扩展中正确接入Flutter Method Channel

iOS分享扩展接入Flutter平台通道实现方案

该需求可实现。

你之前的方案无法生效的核心原因:iOS App Extension(含分享扩展)和主应用是完全独立的进程、独立沙箱环境,不存在主应用的window、rootViewController对象,继承FlutterAppDelegate的思路完全不适用——FlutterAppDelegate是为主应用生命周期设计的,扩展不会走这套生命周期流程,自然拿不到初始化好的Flutter控制器实例。

正确实现步骤

  • 第一步:给分享扩展Target配置Flutter依赖
    打开项目Podfile,找到分享扩展对应的target块,添加Flutter基础依赖,执行pod install完成依赖集成,确保扩展target能正常链接Flutter相关framework。注意不要引入仅支持主应用运行的插件,避免运行时报错。

  • 第二步:在分享扩展的ShareViewController中独立初始化Flutter运行时
    不要尝试获取主应用的Flutter实例,直接在扩展的控制器内初始化独立的Flutter引擎,示例代码如下:

import Flutter
import UIKit

class ShareViewController: UIViewController {
    // 强引用Flutter引擎,避免提前释放导致通道失效
    private var flutterEngine: FlutterEngine?
    private var methodChannel: FlutterMethodChannel?

    override func viewDidLoad() {
        super.viewDidLoad()
        // 初始化独立的Flutter引擎,和主应用引擎互不干扰
        flutterEngine = FlutterEngine(name: "share_extension_engine")
        guard let engine = flutterEngine else { return }
        // 启动引擎,可指定自定义Dart入口,默认入口为main
        engine.run(withEntrypoint: "shareExtensionMain")
        
        // 直接用引擎的binaryMessenger初始化方法通道,无需依赖FlutterViewController
        methodChannel = FlutterMethodChannel(
            name: "task-identifier",
            binaryMessenger: engine.binaryMessenger
        )

        // 如果你需要在扩展中展示Flutter UI,再初始化FlutterViewController添加到视图层级
        let flutterVC = FlutterViewController(engine: engine, nibName: nil, bundle: nil)
        addChild(flutterVC)
        flutterVC.view.frame = view.bounds
        view.addSubview(flutterVC.view)
        flutterVC.didMove(toParent: self)

        // 引擎启动完成后即可正常调用通道方法
        methodChannel?.invokeMethod("fetchImage", arguments: "Arg-s")
    }
}
  • 第三步:在Dart层添加扩展对应的入口逻辑
    给扩展的Flutter逻辑添加独立入口,添加@pragma('vm:entry-point')注解避免该方法被Tree Shaking剔除,示例代码:
import 'package:flutter/services.dart';
import 'package:flutter/widgets.dart';

// 扩展专属入口,和主应用main入口隔离
@pragma('vm:entry-point')
void shareExtensionMain() {
  WidgetsFlutterBinding.ensureInitialized();
  const MethodChannel channel = MethodChannel('task-identifier');
  // 注册通道方法监听
  channel.setMethodCallHandler((call) async {
    switch (call.method) {
      case 'fetchImage':
        final arguments = call.arguments;
        // 处理分享扩展传入的参数,执行业务逻辑
        return "处理完成";
      default:
        throw MissingPluginException();
    }
  });
  // 如果不需要展示Flutter UI可以不调用runApp,需要展示页面则正常传入根组件即可
}

关键注意事项

  • 不要尝试在扩展和主应用之间共享Flutter引擎实例,二者属于不同进程,内存不互通,强行跨进程引用会导致崩溃。
  • 如果仅需要用平台通道传递数据、执行Dart逻辑,不需要展示Flutter页面,可以不用初始化FlutterViewController,只要FlutterEngine调用run方法启动后,通道即可正常通信。
  • iOS系统对分享扩展的内存占用限制远低于主应用,不要在扩展的Flutter环境中运行过重的逻辑,否则会被系统直接终止进程。
  • 自定义的Dart入口必须加@pragma('vm:entry-point')注解,否则在Release模式下会被编译器优化剔除,导致引擎找不到入口报错。

内容的提问来源于stack exchange,提问作者mytakii sergii

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.29 21:15:36