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

Flutter集成Siri:语音指令触发后应用未自动启动跳转

解决Flutter + GetX集成Siri指令后无法自动打开并跳转页面的问题

问题核心原因

当通过Siri触发Intent时,应用可能处于未启动/后台挂起状态,此时Flutter引擎尚未完成初始化,直接通过MethodChannel发送导航指令时,Flutter端还未准备好接收消息,导致指令被“缓存”,直到手动打开应用、引擎初始化完成后才会执行。


解决方案分两步:iOS端确保引擎就绪后发送指令,Flutter端启动时处理缓存指令

1. iOS端(AppDelegate修改)

需要在处理Intent时,先判断Flutter引擎是否已初始化,未初始化则先启动引擎,待引擎就绪后再发送导航指令;同时保存Intent的操作类型,避免冷启动时丢失指令。

import UIKit
import Flutter
import Intents

@UIApplicationMain
class AppDelegate: FlutterAppDelegate {
    // 保存需要执行的导航指令
    private var pendingIntentAction: String?
    // 全局Flutter引擎实例
    lazy var flutterEngine = FlutterEngine(name: "MyFlutterEngine")

    override func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
        // 预初始化Flutter引擎(加快冷启动速度)
        flutterEngine.run()
        GeneratedPluginRegistrant.register(with: self.flutterEngine)
        
        // 检查启动时是否携带Intent指令
        if let activityDict = launchOptions?[.userActivityDictionary] as? [AnyHashable: Any],
           let userActivity = activityDict["UIApplicationLaunchOptionsUserActivityKey"] as? NSUserActivity {
            handleIntentActivity(userActivity)
        }
        
        return super.application(application, didFinishLaunchingWithOptions: launchOptions)
    }

    // 处理Siri Intent的回调
    override func application(_ application: UIApplication, continue userActivity: NSUserActivity, restorationHandler: @escaping ([UIUserActivityRestoring]?) -> Void) -> Bool {
        handleIntentActivity(userActivity)
        return true
    }

    private func handleIntentActivity(_ userActivity: NSUserActivity) {
        guard userActivity.activityType == "com.yourdomain.openHomework" else { return }
        
        pendingIntentAction = "open_homework"
        
        // 判断Flutter引擎是否已就绪
        if flutterEngine.runner.isApplicationRunning {
            sendNavigationCommandToFlutter()
        } else {
            // 监听引擎启动完成事件
            flutterEngine.runner.addEngineLifecycleDelegate(self)
            // 引擎未启动则先启动
            if !flutterEngine.runner.isRunning {
                flutterEngine.run()
                GeneratedPluginRegistrant.register(with: self.flutterEngine)
            }
        }
    }

    private func sendNavigationCommandToFlutter() {
        guard let action = pendingIntentAction else { return }
        let channel = FlutterMethodChannel(name: "com.yourdomain/navigation", binaryMessenger: flutterEngine.binaryMessenger)
        channel.invokeMethod("navigateTo", arguments: ["page": action])
        pendingIntentAction = nil
    }
}

extension AppDelegate: FlutterEngineLifecycleDelegate {
    func engineDidRun(_ engine: FlutterEngine) {
        // 引擎启动完成,发送缓存的导航指令
        sendNavigationCommandToFlutter()
        engine.runner.removeEngineLifecycleDelegate(self)
    }
}

2. Flutter端(GetX导航处理)

需要在应用启动时就初始化MethodChannel并监听指令;同时确保冷启动时能直接处理Intent传递的参数,实现打开即跳转。

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

void main() async {
  WidgetsFlutterBinding.ensureInitialized();
  
  // 提前初始化MethodChannel,确保引擎就绪后能立即接收指令
  const MethodChannel navigationChannel = MethodChannel('com.yourdomain/navigation');
  
  // 监听iOS端发送的导航指令
  navigationChannel.setMethodCallHandler((call) async {
    if (call.method == 'navigateTo') {
      final String page = call.arguments['page'];
      if (page == 'open_homework') {
        // 使用GetX跳转到作业页面
        Get.to(() => HomeworkPage());
      }
    }
  });
  
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return GetMaterialApp(
      title: 'MyApp',
      initialRoute: '/',
      getPages: [
        GetPage(name: '/', page: () => HomePage()),
        GetPage(name: '/homework', page: () => HomeworkPage()),
      ],
    );
  }
}

class HomeworkPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('作业页面')),
      body: Center(child: Text('作业内容')),
    );
  }
}

额外注意事项

  • 确保Intent的activityType、MethodChannel的名称在iOS和Flutter端完全一致,避免拼写错误。
  • 在Xcode的Info.plist中添加NSUserActivityTypes数组,包含你的Intent类型(例如com.yourdomain.openHomework)。
  • 测试前确认Siri快捷指令已正确关联应用,且应用的Siri权限已开启(设置->Siri与搜索->你的应用)。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.18 00:05:15