IOS-Flutter頁面的展示與通訊

IOS端

初始化Engines

/* APP冷啓動之後 */
[[MKFlutterEngineMgr sharedInstance] initEngines];

- (void)initEngines {
    // 多個tab頁多個引擎,二級頁複用單引擎
    NSMutableArray* mArr = [NSMutableArray arrayWithCapacity:2];
    for (int i=0; i<2; i++) {
        FlutterEngine* engine = [[FlutterEngine alloc] initWithName:@"ios_flutter" project:nil];
        [engine runWithEntrypoint:nil];
        [MKPluginRegistrant registerWithRegistry:engine];
        [mArr addObject:engine];
    }
    self.flutterEngines = mArr;
}

 創建FlutterViewController

/* 基於BaseVC的ShowFlutterVC */
FlutterEngine* flutterEngine = [[[MKFlutterEngineMgr sharedInstance] flutterEngines] objectAtIndex:_tabIndex];
self.flutterVC = [[MKFlutterViewController alloc] initWithEngine:flutterEngine  nibName:nil bundle:nil];
self.flutterVC.routeName = _routeName;

通過routeChannel配置路由信息

static NSString * const kFlutterRouteChannelName = @"com.base.test/route";

- (void)initData {
    /* 默認都是StandardCodec,Codec需要保持與flutter端一致 */
    self.routeChannel = [FlutterMethodChannel methodChannelWithName:kFlutterRouteChannelName binaryMessenger:[self binaryMessenger]];
}

- (void)setRouteName:(NSString *)routeName {
    _routeName = [routeName copy];
    [self invokeRoute:@"InitialRoute" arguments:@{@"route":routeName}];
}

- (void)invokeRoute:(NSString*)method arguments:(id _Nullable)arguments {
    [self.routeChannel invokeMethod:method arguments:arguments result:^(id  _Nullable result) {
        
    }];
}

- (BOOL)loadDefaultSplashScreenView {
    return NO;
}

初始化FlutterBridge,實現通知的監聽

- (void)initData {
    
    self.flutterBridge = [[MKFlutterBridgeHandle alloc] initWithContainer:self];
    
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(becomeActiveHandle:) name:UIApplicationDidBecomeActiveNotification object:nil];
}

- (void)becomeActiveHandle:(NSNotification *)notification {
    [self.flutterBridge sendMessageName:@"didBecomeActiveNotification" args:nil];
}

FlutterBridge的具體實現

- (void)initChannels {
    /* 默認都是StandardCodec,Codec需要保持與flutter端一致 */
    self.baseMessageChannel = [FlutterBasicMessageChannel messageChannelWithName:kFlutterMessagehannelName binaryMessenger:[self.container binaryMessenger]];
    
    self.methodChannel = [FlutterMethodChannel methodChannelWithName:kFlutterMethodChannelName binaryMessenger:[self.container binaryMessenger]];
    
    /* flutter調用native方法 */
    [self.methodChannel setMethodCallHandler:^(FlutterMethodCall * _Nonnull call, FlutterResult  _Nonnull result) {
        if(!call.arguments && !call.method) {
            result(FlutterMethodNotImplemented);
            return;
        }
        NSString *method = (NSString *)call.method;
        NSDictionary *arguments = (NSDictionary *)call.arguments;
        NSLog(@"method:%@; arguments:%@", method, arguments);
        result(@"{\"key\":\"value\"}");
    }];
}

/* native調用flutter方法 */
- (void)invokeFlutterMethod:(NSString *)method arguments:(NSString *)arguments result:(FlutterResult )callback {
    [self.methodChannel invokeMethod:method arguments:arguments result:callback];
}

/* 廣播 */
- (void)sendMessageName:(NSString *)messageName args:(id _Nullable)arguments {
    [self.baseMessageChannel sendMessage:@{@"messageName": messageName, @"arguments": arguments?arguments:@""}];
}

FlutterPlugin的具體應用

/* 創建FlutterPlugin */
@interface MKFlutterReportPlugin : NSObject<FlutterPlugin>

@end


static NSString * const kFlutterReportChannelName = @"com.base.test/report";

@implementation MKFlutterReportPlugin

+ (void)registerWithRegistrar:(NSObject<FlutterPluginRegistrar> *)registrar {
    FlutterMethodChannel *channel = [FlutterMethodChannel methodChannelWithName:kFlutterReportChannelName binaryMessenger:[registrar messenger]];
    MKFlutterReportPlugin *instance = [[MKFlutterReportPlugin alloc] init];
    [registrar addMethodCallDelegate:instance channel:channel];
}

- (void)handleMethodCall:(FlutterMethodCall *)call result:(FlutterResult)result {
    NSLog(@"--futter -- call -- method :%@  arguments:%@",call.method,call.arguments);
}

@end
/* 註冊FlutterPlugin */
@interface MKPluginRegistrant : GeneratedPluginRegistrant

@end

@implementation MKPluginRegistrant

+ (void)registerWithRegistry:(NSObject<FlutterPluginRegistry> *)registry {
    [super registerWithRegistry:registry];
    
    [MKFlutterLogPlugin registerWithRegistrar:[registry registrarForPlugin:@"LCFlutterReportPlugin"]];
}

@end

Flutter端

從main函數配置routeChannel,實現路由切換

final t_methodChannel = const MethodChannel('com.base.test/route');

void main() {
  WidgetsFlutterBinding.ensureInitialized();

  t_methodChannel.setMethodCallHandler(platformCallHandler);
}

Future <dynamic> platformCallHandler(MethodCall call) async {
  print("Flutter---" + call.arguments['route']);
  if (call.method == 'InitialRoute') {
    runApp(EnterApp(call.arguments['route']));
  }
  return '';
}

class EnterApp extends StatefulWidget {
  String _routeName;
  EnterApp(this._routeName);
  EnterAppState createState() => EnterAppState();
}

class EnterAppState extends State<EnterApp> {
  @override
  Widget build(BuildContext context) {
    Map routeDic = <String, Widget> {
      "/myApp": MyAppPage(),
      "/home": MyHomePage()
    };
    print('EnterAppState   ===== build   ${widget._routeName}');
    return new MaterialApp(
        title: '測試',
        initialRoute: widget._routeName,
        home: routeDic[widget._routeName],
        /*
        routes:  <String, WidgetBuilder> {
          "/myApp": (context) => MyAppPage(),
          "/home": (context) => MyHomePage()
        }
        */
    );
  }
}

 MyAppPage代碼示例

import 'package:flutter/material.dart';
import 'dart:ui' as ui;

final double kScreenWidth = ui.window.physicalSize.width/ui.window.devicePixelRatio;
final double kScreenHeight = ui.window.physicalSize.height/ui.window.devicePixelRatio;
final double kScreenScale = ui.window.devicePixelRatio;

class MyAppPage extends StatefulWidget {
  @override
  _MyAppPage createState() => _MyAppPage();
}

class _MyAppPage extends State<MyAppPage> {

  static String picUrl = 'http://attachments.gfan.com/forum/201606/25/0001033cc0l90arrt1sf3a.jpg';

  @override
  void initState() {
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("首頁"),
        backgroundColor: Color.fromRGBO(100, 100, 100, 1)
      ),
      drawer: Drawer(
        child: ListView(
            scrollDirection: Axis.vertical,
            itemExtent: 60,
            children: List.generate(50, (index){
              return Container(
                  alignment: Alignment.center,
                  child: Column(
                      mainAxisAlignment: MainAxisAlignment.start ,
                      children: [Text("行數 $index", style: TextStyle(fontSize: 18))]
                  )
              );
            }))
      ),
      bottomNavigationBar: BottomNavigationBar(
        items: [
          BottomNavigationBarItem(icon: Icon(Icons.home, color: Colors.blue), title: Text('首頁', style: TextStyle(color: Colors.blue),)),
          BottomNavigationBarItem(icon: Icon(Icons.shop, color: Colors.black), title: Text('購物', style: TextStyle(color: Colors.black),))
        ],
        onTap: (index) {
          print('tabIndex $index');
        }
      ),
      body:  Center(
        child: ListView(
          padding: EdgeInsets.all(0),
          children: List.generate(8, (index){
              return Column(
                  mainAxisAlignment: MainAxisAlignment.start,
                  children: [
                    Row(
                        mainAxisAlignment: MainAxisAlignment.start,
                        children: [
                          FlatButton(onPressed: () {
                            print('文字 index:${index+1}');
                        }, child: Text('文字 index:${index+1}', textAlign: TextAlign.left,), padding: EdgeInsets.all(10),),
                          Icon(Icons.subway, color: Colors.blue, size: 24, textDirection: TextDirection.ltr),
                        ]
                    ),
                    Row(
                        mainAxisAlignment: MainAxisAlignment.start,
                        children: [
                          FlatButton(onPressed: () {
                            print('圖片 index:${index+1}');
                        }, child: Image.network(picUrl,
                            height: 200, width: kScreenWidth - 20,
                            fit: BoxFit.fill,),
                          padding: EdgeInsets.only(left: 10, right: 10),),
                        ]
                    )
                  ],
              );
          })
        )
      )
    );
  }
}

demo下載(待續) 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章