美文网首页
flutter_boost学习3:iOSNative添加与flu

flutter_boost学习3:iOSNative添加与flu

作者: 独孤流 | 来源:发表于2019-05-19 17:22 被阅读0次

    上一篇:flutter_boost学习2:iOS集成flutter_boost

    前言

    在上一篇集成了flutter_boost后,还缺少flutter调用原生的方法,以及原生调用flutter的相互交互,这一块只要根据flutter提供的文档就能很好的接入使用

    练习GitHub:HybridFlutter

    一、原生设置相关内容可供flutter调用

    1、iOS原生设置可供flutter调用
    2、iOS原生调用flutter的channel
    完整代码如下:

    //
    //  MyFlutterRouter.m
    //  HybridiOS
    //
    //  Created by loneylyflow on 15/05/2019.
    //  Copyright © 2019 Lonely traveller. All rights reserved.
    //
    
    #import "MyFlutterRouter.h"
    #import "MyFlutterViewController.h"
    #import <UIKit/UIKit.h>
    #import "UINavigationController+FDFullscreenPopGesture.h"
    
    @interface MyFlutterRouter() <FlutterStreamHandler>
    @property(nonatomic, copy) FlutterEventSink nativeCallFlutterEventSink;
    @property(nonatomic, strong) UINavigationController *navigationController;
    @end
    
    @implementation MyFlutterRouter
      
    + (instancetype)sharedRouter
    {
        static MyFlutterRouter *_instance = nil;
        static dispatch_once_t onceToken;
        dispatch_once(&onceToken, ^{
            _instance = [[MyFlutterRouter alloc] init];
            // 在这里初始化FlutterViewController
            // 初始化Router
            [FlutterBoostPlugin.sharedInstance startFlutterWithPlatform:_instance onStart:^(FlutterViewController * fvc){
                dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.001 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
                    MyFlutterRouter.sharedRouter.fvc = fvc;
                   
                });
            }];
        });
        return _instance;
    }
    - (void)setFvc:(FlutterViewController *)fvc
    {
        _fvc = fvc;
        if(fvc != nil){
            [self setupFlutterCallNative];
            [self setupNativeCallFlutter];
        }
        
    }
    #pragma mark - FlutterCallNative
    - (void)setupFlutterCallNative
    {
        // 用于Flutter 调用 Native
        // 这个channelname必须与Native里接收的一致
        FlutterMethodChannel *flutterCallNativeChannel = [FlutterMethodChannel methodChannelWithName:@"samples.flutter.io/flutterCallNative" binaryMessenger:self.fvc];
        
        [flutterCallNativeChannel setMethodCallHandler:^(FlutterMethodCall *call, FlutterResult result) {
            NSLog(@"method: %@",call.method);
            NSLog(@"arguments: %@",call.arguments);
            if([@"getBatteryLevel" isEqualToString:call.method]){
    //            result([FlutterError errorWithCode:@"UNAVAILABLE"
    //                                       message:@"iOS ====== Battery info unavailable2222"
    //                                       details:nil]);
                result(@"Battery info iOS 1234567");
            }else if([@"updateUserInfo" isEqualToString:call.method]){
                NSDictionary *params = call.arguments;
                NSInteger userId = [params[@"id"] integerValue];
                NSString *name = params[@"name"];
                result(@{@"id":@1000,
                         @"name":@"story",
                         @"fromId":@(userId),
                         @"fromName":name
                         });
            }else if([@"nativeCallFlutter" isEqualToString:call.method]){
                //batteryChannel cal
            }else if([@"isShowNav" isEqualToString:call.method]){
               result(@(! self.navigationController.childViewControllers.lastObject.fd_prefersNavigationBarHidden));
                
            }else if([@"hideNav" isEqualToString:call.method]){
                self.navigationController.childViewControllers.lastObject.fd_prefersNavigationBarHidden = YES;
                BOOL animited = [call.arguments boolValue];
                [self.navigationController setNavigationBarHidden:YES animated:animited];
                result(@(NO));
            }else if([@"showNav" isEqualToString:call.method]){
                self.navigationController.childViewControllers.lastObject.fd_prefersNavigationBarHidden = NO;
                BOOL animited = [call.arguments boolValue];
                [self.navigationController setNavigationBarHidden:NO animated:animited];
                result(@(YES));
            }
            else{
                result(FlutterMethodNotImplemented);
            }
            
        }];
    }
    #pragma mark - NativeCallFlutter
    - (void)setupNativeCallFlutter
    {
        // 用于Native调用Flutter
        FlutterEventChannel *nativeCallFlutterChannel = [FlutterEventChannel eventChannelWithName:@"samples.flutter.io/nativeCallFlutter" binaryMessenger:self.fvc];
        [nativeCallFlutterChannel setStreamHandler:self];
    }
    - (FlutterError *)onListenWithArguments:(id)arguments eventSink:(FlutterEventSink)events
    {
        self.nativeCallFlutterEventSink = events;
    //    static NSInteger mm = 0;
    //    [NSTimer scheduledTimerWithTimeInterval:1 repeats:YES block:^(NSTimer * _Nonnull timer) {
    //        if (!_eventSink) return;
    //        NSString *txt = [NSString stringWithFormat:@"    iOS倒计时 %ld秒",++mm];
    //        _eventSink(txt);
    //    }];
        return nil;
    }
    - (FlutterError*)onCancelWithArguments:(id)arguments {
        //[[NSNotificationCenter defaultCenter] removeObserver:self];
        self.nativeCallFlutterEventSink = nil;
        return nil;
    }
    - (void)callFluterWithName:(NSString *)name params:(id)params
    {
        if(self.nativeCallFlutterEventSink){
            self.nativeCallFlutterEventSink(@{@"name":name?:@"",@"params":params ?: [NSNull null]});
        }else{
            WS(weakSelf)
            dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
                [weakSelf callFluterWithName:name params:params];
            });
        }
    }
    #pragma mark - push/pop/close
    - (void)openPage:(NSString *)name params:(NSDictionary *)params animated:(BOOL)animated completion:(void (^)(BOOL))completion
    {
            if([params[@"present"] boolValue]){
                MyFlutterViewController *vc = MyFlutterViewController.new;
                [vc setName:name params:params];
                vc.hidesBottomBarWhenPushed = YES;
                [self.navigationController presentViewController:vc animated:animated completion:^{}];
            }else{
                MyFlutterViewController *vc = MyFlutterViewController.new;
                vc.hidesBottomBarWhenPushed = YES;
                [vc setName:name params:params];
                [self.navigationController pushViewController:vc animated:animated];
            }
        }
        
        
    - (void)closePage:(NSString *)uid animated:(BOOL)animated params:(NSDictionary *)params completion:(void (^)(BOOL))completion
    {
        FLBFlutterViewContainer *vc = (id)self.navigationController.presentedViewController;
        if([vc isKindOfClass:FLBFlutterViewContainer.class] && [vc.uniqueIDString isEqual: uid]){
            [vc dismissViewControllerAnimated:animated completion:^{}];
        }else{
            [self.navigationController popViewControllerAnimated:animated];
        }
    }
    - (UINavigationController *)navigationController
    {
        UITabBarController *tabVC = (UITabBarController *)[UIApplication sharedApplication].delegate.window.rootViewController;
        if([tabVC isKindOfClass:[UITabBarController class]]){
            UINavigationController *nav = (UINavigationController *)tabVC.selectedViewController;
            if([nav isKindOfClass:[UINavigationController class]]){
                return nav;
            }else{
                return [[UINavigationController alloc] init];
            }
        }
        return [[UINavigationController alloc] init];
    }
    @end
    
    

    二、flutter设置相关内容可调用Native及被Native调用

    typedef void NativeCallBack(Object event);
    Map<String,NativeCallBack> callbakcs = {};
    
     const EventChannel eventChannel = const EventChannel("samples.flutter.io/nativeCallFlutter");
     const MethodChannel platform = const MethodChannel("samples.flutter.io/flutterCallNative");
    
    
    void main() {
      runApp(MyApp());
    }
    
    
    class MyApp extends StatefulWidget {
      @override
      _MyAppState createState() => _MyAppState();
    }
    
    class _MyAppState extends State<MyApp> {
    
      void _onEvent(Object event)
      {
        if(event is Map){
          String name = event['name'];
          if(callbakcs[name] != null){
            callbakcs[name](event);
          }
        }
    
      }
    
      void _onError(Object error)
      {
        setState(() {
         // _changingStatus = "${error}";
        });
      }
      @override
      void initState() {
        // 接收Native调用
        eventChannel.receiveBroadcastStream().listen(_onEvent,onError:_onError);
        super.initState();
    
        FlutterBoost.singleton.registerPageBuilders({
          'first': (pageName, params, _) => FirstRouteWidget(),
          'second': (pageName, params, _) => SecondRouteWidget(),
          'tab': (pageName, params, _) => TabRouteWidget(),
          'flutterFragment': (pageName, params, _) => FragmentRouteWidget(params),
    
          ///可以在native层通过 getContainerParams 来传递参数
          'flutterPage': (pageName, params, _) {
            print("flutterPage params:$params");
    
            return FlutterRouteWidget();
          },
        });
        FlutterBoost.handleOnStartPage();
      }
    }
    

    具体调用:

    import 'package:flutter/material.dart';
    import 'package:flutter_boost/flutter_boost.dart';
    import 'main.dart';
    import 'package:flutter/services.dart';
    
    class FirstRouteWidget extends StatefulWidget {
    
      @override
      State<StatefulWidget> createState() {
        return new _FirstRouteWidgetState();
      }
    }
    class _FirstRouteWidgetState extends State<FirstRouteWidget>{
    
      String _changingStatus = "init...";
     String _batteryLevel = "leve";
     String _userInfo = "";
     bool _isShowingNav = false;
    
      @override
      void initState() {
        // 接收Native调用
        //callbakcs["isShowNavBar"]= _responseNative;
    
        super.initState();
    //    _getIsNavShow();
      }
    //  void _responseNative(Object event){
    //      setState(() {
    //        _changingStatus  = "${event}";
    //      });
    //  }
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          appBar: AppBar(
            title: Text('First Route'),
            leading: IconButton(icon: Icon(Icons.arrow_back),
              onPressed:(){
                FlutterBoost.singleton.closePageForContext(context);
              } ,
            ),
          ),
          body: Column(
            children: [
              new RaisedButton(
              child: Text('Flutter call Native'),
              onPressed: _getBatteryLevel
            ),
            new Text(_batteryLevel),
            new RaisedButton(
            child: Text('Flutter call updateUserInfo'),
            onPressed: _updateUserInfo
          ),
              new Text(_userInfo),
              new RaisedButton(
                  child: Text(_isShowingNav ? 'hideNav222' : "showNav222"),
                  onPressed: _showOrHideNav
              ),
              new RaisedButton(
                  child: Text('hideNav'),
                  onPressed: (){
                    platform.invokeMethod("hideNav");
                  }
              ),
    
              new RaisedButton(
              child: Text('Open second 3333'),
              onPressed: () {
                FlutterBoost.singleton.openPage("second", {}, animated: true);
              },
            ),
            new Text(_changingStatus)
          ]
          ),
        );
      }
    
    
      Future<Null> _getIsNavShow() async
      {
    
        bool result = false;
        try{
          result = await platform.invokeMethod("isShowNav");
        } on PlatformException catch(e) {
          result = false;
        }
    //    Scaffold
    //        .of(context)
    //        .showSnackBar(new SnackBar(content: new Text("$result")));
        setState(() {
          _isShowingNav = result;
        });
      }
      Future<Null> _showOrHideNav() async
      {
    
        bool result = _isShowingNav;
        try{
          String name = _isShowingNav ? "hideNav" : "showNav";
          result = await platform.invokeMethod(name,false);
        } on PlatformException catch(e) {
    
        }
    
        setState(() {
          _isShowingNav = result;
        });
      }
    
      Future<Null> _getBatteryLevel() async
      {
        String batteryLevel;
        try{
          final String result = await platform.invokeMethod("getBatteryLevel");
          batteryLevel = "Battery level at $result % .";
        } on PlatformException catch(e) {
          batteryLevel = "Failed to get battery level: '${e.message}'.";
        }
    
        setState(() {
          _batteryLevel = batteryLevel;
        });
      }
    
      Future<Null>  _updateUserInfo() async
      {
        String msg;
        try{
          final Map result = await platform.invokeMethod("updateUserInfo",{"id":10,"name":"Kusina"});
          msg = "Battery level at $result % .";
        } on PlatformException catch(e) {
          msg = "Failed to get battery level: '${e.message}'.";
        }
    
        setState(() {
          _userInfo = msg;
        });
      }
    }
    
    class SecondRouteWidget extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          appBar: AppBar(
            title: Text("Second Route"),
          ),
          body: Center(
            child: RaisedButton(
              onPressed: () {
                // Navigate back to first route when tapped.
                FlutterBoost.singleton.closePageForContext(context);
              },
              child: Text('Go back!'),
            ),
          ),
        );
      }
    }
    
    class TabRouteWidget extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          appBar: AppBar(
            title: Text("Tab Route"),
          ),
          body: Center(
            child: RaisedButton(
              onPressed: () {
                FlutterBoost.singleton.openPage("second", {}, animated: true);
              },
              child: Text('Open second route'),
            ),
          ),
        );
      }
    }
    
    class FlutterRouteWidget extends StatelessWidget {
      final String message;
    
      FlutterRouteWidget({this.message});
    
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          appBar: AppBar(
            title: Text('flutter_boost_example'),
          ),
          body: Column(
            crossAxisAlignment: CrossAxisAlignment.start,
            children: <Widget>[
              Container(
                margin: const EdgeInsets.only(top: 80.0),
                child: Text(
                  message ?? "This is a flutter activity",
                  style: TextStyle(fontSize: 28.0, color: Colors.blue),
                ),
                alignment: AlignmentDirectional.center,
              ),
              Expanded(child: Container()),
              InkWell(
                child: Container(
                    padding: const EdgeInsets.all(8.0),
                    margin: const EdgeInsets.all(8.0),
                    color: Colors.yellow,
                    child: Text(
                      'open native page',
                      style: TextStyle(fontSize: 22.0, color: Colors.black),
                    )),
    
                ///后面的参数会在native的IPlatform.startActivity方法回调中拼接到url的query部分。
                ///例如:sample://nativePage?aaa=bbb
                onTap: () =>
                    FlutterBoost.singleton.openPage("sample://nativePage", {
                      "query": {"aaa": "bbb"}
                    }),
              ),
              InkWell(
                child: Container(
                    padding: const EdgeInsets.all(8.0),
                    margin: const EdgeInsets.all(8.0),
                    color: Colors.yellow,
                    child: Text(
                      'open flutter page',
                      style: TextStyle(fontSize: 22.0, color: Colors.black),
                    )),
    
                ///后面的参数会在native的IPlatform.startActivity方法回调中拼接到url的query部分。
                ///例如:sample://nativePage?aaa=bbb
                onTap: () =>
                    FlutterBoost.singleton.openPage("sample://flutterPage", {
                      "query": {"aaa": "bbb"}
                    }),
              ),
              InkWell(
                child: Container(
                    padding: const EdgeInsets.all(8.0),
                    margin: const EdgeInsets.all(8.0),
                    color: Colors.yellow,
                    child: Text(
                      'push flutter widget',
                      style: TextStyle(fontSize: 22.0, color: Colors.black),
                    )),
                onTap: () {
                  Navigator.push(
                      context, MaterialPageRoute(builder: (_) => PushWidget()));
                },
              ),
              InkWell(
                child: Container(
                    padding: const EdgeInsets.all(8.0),
                    margin: const EdgeInsets.fromLTRB(8.0, 8.0, 8.0, 80.0),
                    color: Colors.yellow,
                    child: Text(
                      'open flutter fragment page',
                      style: TextStyle(fontSize: 22.0, color: Colors.black),
                    )),
                onTap: () => FlutterBoost.singleton
                    .openPage("sample://flutterFragmentPage", {}),
              )
            ],
          ),
        );
      }
    }
    
    class FragmentRouteWidget extends StatelessWidget {
      final Map params;
    
      FragmentRouteWidget(this.params);
    
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          appBar: AppBar(
            title: Text('flutter_boost_example'),
          ),
          body: Column(
            crossAxisAlignment: CrossAxisAlignment.start,
            children: <Widget>[
              Container(
                margin: const EdgeInsets.only(top: 80.0),
                child: Text(
                  "This is a flutter fragment",
                  style: TextStyle(fontSize: 28.0, color: Colors.blue),
                ),
                alignment: AlignmentDirectional.center,
              ),
              Container(
                margin: const EdgeInsets.only(top: 32.0),
                child: Text(
                  params['tag'] ?? '',
                  style: TextStyle(fontSize: 28.0, color: Colors.red),
                ),
                alignment: AlignmentDirectional.center,
              ),
              Expanded(child: Container()),
              InkWell(
                child: Container(
                    padding: const EdgeInsets.all(8.0),
                    margin: const EdgeInsets.all(8.0),
                    color: Colors.yellow,
                    child: Text(
                      'open native page',
                      style: TextStyle(fontSize: 22.0, color: Colors.black),
                    )),
                onTap: () =>
                    FlutterBoost.singleton.openPage("sample://nativePage", {}),
              ),
              InkWell(
                child: Container(
                    padding: const EdgeInsets.all(8.0),
                    margin: const EdgeInsets.all(8.0),
                    color: Colors.yellow,
                    child: Text(
                      'open flutter page',
                      style: TextStyle(fontSize: 22.0, color: Colors.black),
                    )),
                onTap: () =>
                    FlutterBoost.singleton.openPage("sample://flutterPage", {}),
              ),
              InkWell(
                child: Container(
                    padding: const EdgeInsets.all(8.0),
                    margin: const EdgeInsets.fromLTRB(8.0, 8.0, 8.0, 80.0),
                    color: Colors.yellow,
                    child: Text(
                      'open flutter fragment page',
                      style: TextStyle(fontSize: 22.0, color: Colors.black),
                    )),
                onTap: () => FlutterBoost.singleton
                    .openPage("sample://flutterFragmentPage", {}),
              )
            ],
          ),
        );
      }
    }
    
    class PushWidget extends StatefulWidget {
      @override
      _PushWidgetState createState() => _PushWidgetState();
    }
    
    class _PushWidgetState extends State<PushWidget> {
      VoidCallback _backPressedListenerUnsub;
    
      @override
      void initState() {
        // TODO: implement initState
        super.initState();
      }
    
      @override
      void didChangeDependencies() {
        // TODO: implement didChangeDependencies
        super.didChangeDependencies();
    
    //    if (_backPressedListenerUnsub == null) {
    //      _backPressedListenerUnsub =
    //          BoostContainer.of(context).addBackPressedListener(() {
    //        if (BoostContainer.of(context).onstage &&
    //            ModalRoute.of(context).isCurrent) {
    //          Navigator.pop(context);
    //        }
    //      });
    //    }
      }
    
      @override
      void dispose() {
        // TODO: implement dispose
        super.dispose();
        _backPressedListenerUnsub?.call();
      }
    
      @override
      Widget build(BuildContext context) {
        return FlutterRouteWidget(message:"Pushed Widget");
      }
    }
    
    

    完整内容参考:HybridFlutter

    相关文章

      网友评论

          本文标题:flutter_boost学习3:iOSNative添加与flu

          本文链接:https://www.haomeiwen.com/subject/vgeqzqtx.html