Flutter iOS (Scene-based) で xcrun simctl openurl 用の Custom URL Scheme を実装する
Swift
Flutter
iOS
go_router
知識
運用
ローカル開発で外部から特定の go_router ルートに直行できるようにする手順。Hot Reload を保ったまま AI/CLI から画面遷移できる。
- ios/Runner/Info.plist に CFBundleURLTypes を追加し scheme を登録
- FlutterSceneDelegate を継承した SceneDelegate で scene(_:openURLContexts:) をオーバーライドし、URL 受信時に flutter/navigation チャネル経由で pushRoute を送出
- cold start 用に scene(_:willConnectTo:options:) でも connectionOptions.urlContexts を拾って同様に転送(Flutter 起動直後に届くよう少し遅延)
- Dart 側は MaterialApp.router(routerConfig: ...) 経由で go_router が PlatformRouteInformationProvider を自動利用するため追加配線不要
呼び出し例: xcrun simctl openurl booted myscheme:///agenda → /agenda ルートへ遷移。
注意点:
- Info.plist 変更は full rebuild が必要(flutter run 中の Hot Reload/Restart では反映されない)。flutter build ios --debug --simulator --no-codesign → simctl install → simctl launch の順
- Hot Reload を後から復元したい場合は別ターミナルで flutter attach -d <device-id>
- 旧 AppDelegate-only のプロジェクトと違い、Scene-based では application:openURL: ではなく Scene 側のコールバックで受ける
SceneDelegate サンプル:
swift
class SceneDelegate: FlutterSceneDelegate {
override func scene(_ scene: UIScene, openURLContexts URLContexts: Set<UIOpenURLContext>) {
super.scene(scene, openURLContexts: URLContexts)
guard let url = URLContexts.first?.url else { return }
forwardToFlutter(url: url)
}
override func scene(_ scene: UIScene, willConnectTo session: UISceneSession,
options connectionOptions: UIScene.ConnectionOptions) {
super.scene(scene, willConnectTo: session, options: connectionOptions)
if let url = connectionOptions.urlContexts.first?.url {
DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) { [weak self] in
self?.forwardToFlutter(url: url)
}
}
}
private func forwardToFlutter(url: URL) {
guard let window = self.window,
let flutterVC = window.rootViewController as? FlutterViewController else { return }
let channel = FlutterMethodChannel(name: "flutter/navigation",
binaryMessenger: flutterVC.binaryMessenger)
let path = (url.path.isEmpty ? "/" : url.path) + (url.query.map { "?\($0)" } ?? "")
channel.invokeMethod("pushRoute", arguments: path)
}
}