Flutter引擎在iOS通知服务扩展中MethodChannel无法回传数据
问题:iOS通知服务扩展中Flutter引擎无法回传数据
已将Flutter模块编译为框架并添加到Xcode的通知服务扩展目标中,目前数据可成功发送至Flutter端,但始终无法接收返回值——无论是用return还是invokeMethod都无效。在纯iOS App的AppDelegate中调用该模块时功能正常,但在通知扩展里只能成功运行引擎、发送数据到Flutter,收不到返回结果。怀疑是通知扩展的生命周期特性(非完整App,仅为回调)导致,或是引擎/通道注册存在遗漏。
iOS端代码(NotificationService.swift)
import Flutter import UserNotifications let flutterEngine = FlutterEngine(name: "The engine") let flutterDataChannel = FlutterMethodChannel(name: "com.test.shouldwork/ios", binaryMessenger: flutterEngine.binaryMessenger) class NotificationService: UNNotificationServiceExtension { var contentHandler: ((UNNotificationContent) -> Void)? var bestAttemptContent: UNMutableNotificationContent? override func didReceive(_ request: UNNotificationRequest, withContentHandler contentHandler: @escaping (UNNotificationContent) -> Void) { self.contentHandler = contentHandler bestAttemptContent = (request.content.mutableCopy() as? UNMutableNotificationContent) if let bestAttemptContent = bestAttemptContent { // 初始化引擎 flutterEngine.run() DispatchQueue.main.asyncAfter(deadline: .now() + 1) { struct Content:Codable{ var title:String var body:String } let content = Content(title:bestAttemptContent.title,body: bestAttemptContent.body) var data:Data do{ data = try JSONEncoder().encode(content) let convertedString = String(data: data, encoding: .utf8)! flutterDataChannel.invokeMethod("dataToFlutter", arguments: convertedString, result:{(result) -> () in var request = URLRequest(url: URL(string: "https://us-central1-wellenbrecher-3c570.cloudfunctions.net/debug?data=isback")!) let task = URLSession.shared.dataTask(with: request) task.resume() let result = result as! NSDictionary //bestAttemptContent.title = result["title"] as! String //bestAttemptContent.body = result["body"] as! String$ bestAttemptContent.title = "was mutated !" contentHandler(bestAttemptContent) }) } catch{ print("error") } } } } override func serviceExtensionTimeWillExpire() { // 扩展即将被系统终止前调用,需返回修改后的内容或原 payload if let contentHandler = contentHandler, let bestAttemptContent = bestAttemptContent { contentHandler(bestAttemptContent) } } }
Dart端代码(main.dart)
import 'dart:convert'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:http/http.dart' as http; final platform = const MethodChannel('com.test.shouldwork/ios'); notification_extension(data){ data['title']= "Hello world !"; return data; } Future<void> _receiveFromNative(MethodCall call) async { try { if (call.method == "dataToFlutter") { final String data = call.arguments; http.get(Uri.parse('https://us-central1-wellenbrecher-3c570.cloudfunctions.net/debug?data=$data')); var jData = await jsonDecode(data); var jResult = notification_extension(jData); return jResult; } } on PlatformException catch (error) { print(error); } } main() async { WidgetsFlutterBinding.ensureInitialized(); http.get(Uri.parse('https://us-central1-wellenbrecher-3c570.cloudfunctions.net/debug?flutter=true')); try{ platform.setMethodCallHandler(_receiveFromNative); } catch (e){ http.get(Uri.parse('https://us-central1-wellenbrecher-3c570.cloudfunctions.net/debug?isReady_error=$e')); } }
解决方案
1. 修正Dart方法的返回类型
你的Dart端_receiveFromNative方法声明为Future<void>,但要返回数据给Native端,必须改为返回Future<dynamic>(或具体类型),否则Native端无法接收返回值:
Future<dynamic> _receiveFromNative(MethodCall call) async { try { if (call.method == "dataToFlutter") { final String data = call.arguments; http.get(Uri.parse('https://us-central1-wellenbrecher-3c570.cloudfunctions.net/debug?data=$data')); var jData = await jsonDecode(data); var jResult = notification_extension(jData); return jResult; } return null; // 处理未匹配的方法调用 } on PlatformException catch (error) { print(error); return error; // 将异常回传给Native端 } }
2. 替换不可靠的延迟等待,监听引擎初始化完成
用固定延迟等待引擎初始化不可靠,改为监听引擎启动完成事件,确保通道注册成功后再调用方法:
override func didReceive(_ request: UNNotificationRequest, withContentHandler contentHandler: @escaping (UNNotificationContent) -> Void) { self.contentHandler = contentHandler bestAttemptContent = (request.content.mutableCopy() as? UNMutableNotificationContent) guard let bestAttemptContent = bestAttemptContent else { contentHandler(request.content) return } // 监听引擎初始化完成事件 flutterEngine.run(withEntrypoint: nil) { [weak self] result in guard let self = self, result == .success else { contentHandler(bestAttemptContent) return } struct Content: Codable { var title: String var body: String } let content = Content(title: bestAttemptContent.title, body: bestAttemptContent.body) do { let data = try JSONEncoder().encode(content) guard let convertedString = String(data: data, encoding: .utf8) else { contentHandler(bestAttemptContent) return } self.flutterDataChannel.invokeMethod("dataToFlutter", arguments: convertedString) { result in // 安全处理返回值,避免强制类型转换崩溃 if let resultDict = result as? [String: Any], let newTitle = resultDict["title"] as? String { bestAttemptContent.title = newTitle } else { bestAttemptContent.title = "was mutated !" } contentHandler(bestAttemptContent) } } catch { print(error) contentHandler(bestAttemptContent) } } }
3. 适配通知扩展的生命周期限制
通知扩展的运行时间被系统严格限制(通常仅几秒),需优化流程:
- 移除调试用的网络请求,减少耗时
- 用Release模式编译Flutter框架,加快引擎初始化速度
- 在
serviceExtensionTimeWillExpire方法中兜底返回内容,避免系统强制终止扩展
内容的提问来源于stack exchange,提问作者aloys-c
相关产品推荐
相关产品推荐

