实现Flutter应用从浏览器接收文本时的启动与自动唤起导航
解决Flutter应用后台运行时无法从浏览器唤起并展示选中文本的问题
问题分析
你用flutter_process_text实现了文本接收,但应用在后台运行时,只能通过流接收文本却无法自动唤起到前台,必须手动打开才能看到内容。这是因为该包默认只处理文本传递逻辑,没有覆盖应用前台唤起的原生系统行为,需要针对Android和iOS分别补充原生代码实现。
解决方案
Android 端配置与代码修改
确认Manifest的Intent Filter配置
打开android/app/src/main/AndroidManifest.xml,检查主Activity的intent-filter,必须包含DEFAULT和LAUNCHER类别,确保系统能识别并唤起应用:<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> <!-- flutter_process_text 所需的文本处理规则 --> <intent-filter> <action android:name="android.intent.action.PROCESS_TEXT" /> <category android:name="android.intent.category.DEFAULT" /> <data android:mimeType="text/plain" /> </intent-filter> </activity>重写MainActivity的onNewIntent方法
应用后台运行时,新的文本Intent会通过onNewIntent传递,这里要处理文本并将应用唤起到前台:import android.content.Intent 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/text_channel" private var methodChannel: MethodChannel? = null override fun configureFlutterEngine(flutterEngine: FlutterEngine) { super.configureFlutterEngine(flutterEngine) methodChannel = MethodChannel(flutterEngine.dartExecutor.binaryMessenger, CHANNEL) } override fun onNewIntent(intent: Intent) { super.onNewIntent(intent) // 将应用唤起至前台 moveTaskToBack(false) startActivity(intent) // 提取文本并传递给Flutter val text = intent.getStringExtra(Intent.EXTRA_PROCESS_TEXT) text?.let { methodChannel?.invokeMethod("receiveText", it) } } }
iOS 端配置与代码修改
Info.plist 配置文本处理权限
打开ios/Runner/Info.plist,添加文本处理扩展配置:<key>NSExtension</key> <dict> <key>NSExtensionAttributes</key> <dict> <key>NSExtensionActivationRule</key> <dict> <key>NSExtensionActivationSupportsText</key> <true/> </dict> </dict> <key>NSExtensionMainStoryboard</key> <string>MainInterface</string> <key>NSExtensionPointIdentifier</key> <string>com.apple.ui-services</string> </dict>处理应用唤起与文本传递
若使用AppDelegate(iOS 12及以下),修改AppDelegate.swift:import UIKit import Flutter @UIApplicationMain class AppDelegate: FlutterAppDelegate { private let CHANNEL = "com.your_app/text_channel" override func application( _ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? ) -> Bool { let controller = window?.rootViewController as! FlutterViewController let methodChannel = FlutterMethodChannel(name: CHANNEL, binaryMessenger: controller.binaryMessenger) GeneratedPluginRegistrant.register(with: self) return super.application(application, didFinishLaunchingWithOptions: launchOptions) } override funccation(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey : Any] = [:]) -> Bool { // 唤起应用到前台 app.activate(animated: true) // 提取文本并传递给Flutter if let text = url.host { let controller = window?.rootViewController as! FlutterViewController let methodChannel = FlutterMethodChannel(name: CHANNEL, binaryMessenger: controller.binaryMessenger) methodChannel.invokeMethod("receiveText", arguments: text) } return true } }若使用SceneDelegate(iOS 13+),修改
SceneDelegate.swift的对应方法:func scene(_ scene: UIScene, openURLContexts URLContexts: Set<UIOpenURLContext>) { guard let url = URLContexts.first?.url else { return } // 唤起应用到前台 UIApplication.shared.activate(animated: true) // 提取文本并传递给Flutter if let text = url.host { let controller = window?.rootViewController as! FlutterViewController let methodChannel = FlutterMethodChannel(name: "com.your_app/text_channel", binaryMessenger: controller.binaryMessenger) methodChannel.invokeMethod("receiveText", arguments: text) } }
Flutter 端整合逻辑
同时监听flutter_process_text的流和原生通道的回调,确保两种场景都能接收并展示文本:
import 'package:flutter/material.dart'; import 'package:flutter_process_text/flutter_process_text.dart'; import 'package:flutter/services.dart'; void main() => runApp(const MyApp()); class MyApp extends StatefulWidget { const MyApp({super.key}); @override State<MyApp> createState() => _MyAppState(); } class _MyAppState extends State<MyApp> { String _receivedText = ""; final MethodChannel _channel = const MethodChannel("com.your_app/text_channel"); @override void initState() { super.initState(); // 监听flutter_process_text的文本流(冷启动场景) FlutterProcessText.processTextStream.listen((text) { setState(() => _receivedText = text); }); // 监听原生通道的文本回调(后台唤起场景) _channel.setMethodCallHandler((call) async { if (call.method == "receiveText") { setState(() => _receivedText = call.arguments as String); } }); } @override Widget build(BuildContext context) { return MaterialApp( home: Scaffold( appBar: AppBar(title: const Text("文本接收测试")), body: Center( child: Text("收到的文本:\n$_receivedText"), ), ), ); } }
关键说明
- Android的
moveTaskToBack(false)和iOS的app.activate(animated: true)是唤起应用到前台的核心逻辑。 - 原生通道用来补充
flutter_process_text在后台唤起场景下的文本传递能力,确保应用前台后能立即更新UI展示文本。 - 测试前需重新打包安装应用,避免缓存导致配置不生效。
内容的提问来源于stack exchange,提问作者Talha
相关产品推荐
相关产品推荐

