iOS 工程實現native 跳轉指定的Flutter 頁面


概要

前一篇文章中我們提到,iOS跳轉到Flutter工程指定頁面時(多個),Flutter只有單例,設置setInitialRouter 無效,如下

  let flutterViewController = FlutterViewController(engine: flutterEngine, nibName: nil, bundle: nil)!
        flutterViewController.setInitialRoute("test1")

基於不是很甘心,一直想實現完美的解決方案,所以最近幾天又看了下解決各方面的解決方案,最終還是有了可行方案,步驟如下

1、設置delegate 代碼

 這里代碼 多了 FlutterBasicMessageChannel’  設置,其中_kReloadChannelName要和 flutter上的代碼保持一致

let _kReloadChannelName = "reload"

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate ,FlutterAppLifeCycleProvider{
   
    
    static var shared: AppDelegate?
        
    var window: UIWindow?
 
    var _lifeCycleDelegate = FlutterPluginAppLifeCycleDelegate()
    var flutterEngine : FlutterEngine!
    var  flutterViewController : RKFlutterViewController!
    var  reloadMessageChannel : FlutterBasicMessageChannel!
    
    func addApplicationLifeCycleDelegate(_ delegate: FlutterPlugin) {
        _lifeCycleDelegate.add(delegate)
    }
    
    func flutterSetup(){
        flutterEngine = FlutterEngine(name: "rokid.flutter", project: nil)
        flutterEngine.run(withEntrypoint: nil)
        //全局引擎(解決啟動加載時候m,無法處理和native交互問題)
        flutterViewController = RKFlutterViewController(engine: flutterEngine, nibName: nil, bundle: nil)!
        GeneratedPluginRegistrant.register(with: flutterEngine)
        //實現App 路由跳轉
        reloadMessageChannel = FlutterBasicMessageChannel(name: _kReloadChannelName, binaryMessenger: flutterEngine, codec: FlutterStringCodec.sharedInstance())
    }
    
    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
        ...
        flutterSetup()
       ...
}    

 

2、iOS App 跳轉指定路由 

 

   @objc func handleButtonAction() {
         self.engine().navigationChannel.invokeMethod("setInitialRoute", arguments: "test")
        self.reloadMessageChannel().sendMessage("test")
        let flutterViewController = FlutterViewController(engine: self.engine(), nibName: nil, bundle: nil)!
        self.navigationController?.pushViewController(flutterViewController, animated: true)
    }


 func engine() -> FlutterEngine {
        return (UIApplication.shared.delegate! as! AppDelegate).flutterEngine
    }
    
    func reloadMessageChannel() -> FlutterBasicMessageChannel {
        return (UIApplication.shared.delegate! as! AppDelegate).reloadMessageChannel
    }

 

3、flutter路由代碼如下

 

import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'dart:ui' as ui;
import 'src/pages/playground/PlaygroundPage.dart';

/// Channel used to let the Flutter app know to reset the app to a specific
/// route.  See the [run] method.
///
/// Note that we shouldn't use the `setInitialRoute` method on the system
/// navigation channel, as that never gets propagated back to Flutter after the
/// initial call.
const String _kReloadChannelName = 'reload';
const BasicMessageChannel<String> _kReloadChannel =
BasicMessageChannel<String>(_kReloadChannelName, StringCodec());


void main(){
  // Start listening immediately for messages from the iOS side. ObjC calls
  // will be made to let us know when we should be changing the app state.
  _kReloadChannel.setMessageHandler(run);
  // Start off with whatever the initial route is supposed to be.
  run(ui.window.defaultRouteName);
}


Future<String> run(String name) async{
  // The platform-specific component will call [setInitialRoute] on the Flutter
  // view (or view controller for iOS) to set [ui.window.defaultRouteName].
  // We then dispatch based on the route names to show different Flutter
  // widgets.
  // Since we don't really care about Flutter-side navigation in this app, we're
  // not using a regular routes map.
  switch (name) {
    case "test":
      runApp(appRouter(title: "我是路由測試test00",));
      break;
    case "test1":
      runApp(appRouter(title: "我是路由測試test01",));
      break;
    case "test2":
      runApp(appRouter(title: "我是路由測試test02",));
      break;
    default:
      runApp(MyApp());
      break;
  }
  return '';
}

class  appRouter extends StatelessWidget {
  appRouter({this.title});

  final String title;
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter rokid',
      debugShowCheckedModeBanner: false,// 顯示和隱藏
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: PlaygroundPage(title: '$title'),
    );
  }
}


class MyApp extends StatelessWidget {
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter rokid',
      debugShowCheckedModeBanner: false,// 顯示和隱藏
      theme: ThemeData(
        // This is the theme of your application.
        //
        // Try running your application with "flutter run". You'll see the
        // application has a blue toolbar. Then, without quitting the app, try
        // changing the primarySwatch below to Colors.green and then invoke
        // "hot reload" (press "r" in the console where you ran "flutter run",
        // or press Run > Flutter Hot Reload in a Flutter IDE). Notice that the
        // counter didn't reset back to zero; the application is not restarted.
        primarySwatch: Colors.blue,
      ),
      home: PlaygroundPage(title: '若琪實驗室'),
      routes: <String ,WidgetBuilder>{
        "router1": (_) => new PlaygroundPage(title: "我是內部路由測試test00",),
        "router2": (_) => new PlaygroundPage(title: "我是內部路由測試test01",)
    },
    );
  }
}

思考和總結

 上面代碼可以實現:native -> 任意 flutter   ,但是flutter Engine是單例子,能否實現 native->flutter ->native->flutter呢?

功能和交互如何去選擇呢???

參考資料

https://github.com/flutter/flutter/issues/27882

https://github.com/flutter/flutter/blob/master/dev/integration_tests/ios_add2app/ios_add2app/MainViewController.m

https://github.com/flutter/flutter/blob/master/dev/integration_tests/ios_add2app/flutterapp/lib/main.dart

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM