flutter和iOS混编,并且在iOS中控制跳转不同的flutter页面

//main

import 'package:flutter/material.dart';
import 'package:use_with_native/native_system_call.dart';
import 'test_page_blue.dart';
import 'test_page_red.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: '原生和Flutter相互跳转',
      theme: ThemeData(
        primarySwatch: Colors.green,
      ),
      home: MyHomePage(
        title: '',
        pageType: '',
      ),
    );
  }
}

class MyHomePage extends StatefulWidget {
  MyHomePage({Key key, this.title, this.pageType}) : super(key: key);

  final String title;
  final String pageType;

  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  String pageType = '';
  String identity = '';
  Map param = Map();
  @override
  void initState() {
    super.initState();
    getCurrentPageType();
  }

  @override
  Widget build(BuildContext context) {
    return createCurrentPage();
  }

  @override
  void dispose() {
    super.dispose();
    NativeSystemCall.removeStateWithIdentity(this.identity);
  }

  getCurrentPageType() async {
    try {
      Map result = await NativeSystemCall.systemCall
          .invokeMapMethod('ui', {'event': 'getNewPageInfo'});
      String type = result['type'];
      String identity = result['identity'];
      Map param = result['param'];
      setState(() {
        this.pageType = type;
        this.identity = identity;
        this.param = param == null ? Map() : param;
        NativeSystemCall.addStateWithIdentity(this, identity);
      });
    } catch (e) {}
  }

  closeThisPage() {
    try {
      NativeSystemCall.systemCall
          .invokeMethod('ui', {'event': 'dismissTopPage'});
    } catch (e) {}
  }

  Widget createCurrentPage() {
    Widget pageContent = Center();
    switch (pageType) {
      case 'red':
        pageContent = TestPageRed(
          param: this.param,
          backEvent: closeThisPage,
        );
        break;
      case 'blue':
        pageContent = TestPageBlue(
          param: this.param,
          backEvent: closeThisPage,
        );
        break;
      default:
    }
    return pageContent;
  }
}
//native_system_call.dart

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

class NativeSystemCall {
  static Map stateCollection = Map();
  static MethodChannel systemCall =
      MethodChannel('common.flutter.caller/message');

  static findState(String identity) {
    State result = stateCollection[identity];
    return result;
  }

  static addStateWithIdentity(State state, String identity) {
    stateCollection[identity] = state;
  }

  static removeStateWithIdentity(String identity) {
    stateCollection.remove(identity);
  }
}
import 'package:flutter/material.dart';

class TestPageRed extends StatelessWidget {
  TestPageRed({Key key, this.param, this.backEvent}) : super(key: key);
  final Map param;
  final Function backEvent;
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        backgroundColor: Colors.red,
        leading: BackButton(
          onPressed: backEvent,
        ),
        title: Text('测试页面A'),
      ),
      body: Container(
        child: Image(
          image: NetworkImage(
              'https://avatars2.githubusercontent.com/u/41252899?s=460&v=4'),
        ),
      ),
    );
  }
}
//
//  FlutterHelper.m
//  Runner
//
//  Created by wangjiayuan on 2021/4/29.
//

#import "FlutterHelper.h"
#import <objc/runtime.h>

@interface FlutterViewController (FlutterHelper)

@property (nonatomic, copy, readwrite) NSString *pageIdentify;

@end

@implementation FlutterViewController (FlutterHelper)

- (NSString *)pageIdentify {
    return objc_getAssociatedObject(self, "pageIdentify");
}

- (void)setPageIdentify:(NSString *)pageIdentify {
    objc_setAssociatedObject(self, "pageIdentify", pageIdentify, OBJC_ASSOCIATION_COPY_NONATOMIC);
}

@end

@interface FlutterNewPageInfo : NSObject

@property (nonatomic, copy) NSString *pageType;
@property (nonatomic, copy) NSString *pageIdentify;
@property (nonatomic, strong) NSDictionary *pageParam;

@end

@implementation FlutterNewPageInfo


@end

@interface FlutterHelper()

@property (nonatomic, strong) FlutterNewPageInfo *pageInfo;
@property (nonatomic, strong) NSMutableArray <FlutterViewController*> *presentFlutterControllers;

@end

@implementation FlutterHelper

+ (instancetype)helper {
    static FlutterHelper *helper = nil;
    if (!helper) {
        static dispatch_once_t onceToken;
        dispatch_once(&onceToken, ^{
            helper = [[self alloc] init];
        });
    }
    return helper;
}

- (instancetype)init {
    self = [super init];
    if (self) {
        self.presentFlutterControllers = [NSMutableArray array];
    }
    return self;
}

- (void)openNewFlutterPage:(NSString *)pageType {
    self.pageInfo = [FlutterNewPageInfo new];
    self.pageInfo.pageIdentify = [NSString stringWithFormat:@"%.0f%04d", [NSDate date].timeIntervalSince1970, arc4random()%10000];
    self.pageInfo.pageParam = @{};
    self.pageInfo.pageType = pageType;
    FlutterEngine *engine = [[FlutterEngine alloc] initWithName:[NSString stringWithFormat:@"app.flutter.engine:%@", self.pageInfo.pageIdentify]];
    [engine run];
    FlutterViewController *controller = [[FlutterViewController alloc] initWithEngine:engine nibName:nil bundle:nil];
    controller.pageIdentify = self.pageInfo.pageIdentify;

   [GeneratedPluginRegistrant registerWithRegistry:controller.pluginRegistry];

    FlutterMethodChannel *caller = [FlutterMethodChannel methodChannelWithName:@"common.flutter.caller/message" binaryMessenger:controller.binaryMessenger];
    __weak typeof(self) weakSelf = self;
    [caller setMethodCallHandler:^(FlutterMethodCall *call, FlutterResult result) {
        __strong typeof(weakSelf) strongSelf = weakSelf;
        [strongSelf execFlutterCall:call callback:result];
    }];
    controller.modalPresentationStyle = UIModalPresentationFullScreen;
    dispatch_async(dispatch_get_main_queue(), ^{
        [[UIApplication sharedApplication].delegate.window.rootViewController presentViewController:controller animated:YES completion:nil];
        [self.presentFlutterControllers addObject:controller];
    });
}

- (void)execFlutterCall:(FlutterMethodCall*)call callback:(FlutterResult)callback {
    NSString *method = call.method;
    if ([method isEqualToString:@"ui"]) {
        if ([call.arguments isKindOfClass:[NSDictionary class]]) {
            NSDictionary *info = call.arguments;
            NSString *event = info[@"event"];
            if ([event isEqualToString:@"getNewPageInfo"]) {
                !callback?:callback(@{
                    @"type": self.pageInfo.pageType ? : @"",
                    @"identity": self.pageInfo.pageIdentify ? : @"",
                    @"param": self.pageInfo.pageParam ? : @{},
                                    });
                self.pageInfo = nil;
            }
            if ([event isEqualToString:@"dismissTopPage"]) {
                if (self.presentFlutterControllers.count != 0) {
                    FlutterViewController *controller = self.presentFlutterControllers[self.presentFlutterControllers.count - 1];
                    [self.presentFlutterControllers removeObject:controller];
                    [controller dismissViewControllerAnimated:YES completion:^{
                        !callback ? : callback(@(YES));
                    }];
                } else {
                    !callback ? : callback(@(NO));
                }
            }
        }
    }
}

@end

AppDelegate可以和正常的写法一致,每新建一个FlutterEngine就是相当于从新创建一个Flutter运行环境,如果公用一个的话,会出现 State 的 initState 只执行一次,可以理解成,多个 FlutterViewController 负责渲染出来的是同一份 Flutter页面

posted @ 2021-04-29 16:33  雨筱逸悠  阅读(1760)  评论(0编辑  收藏  举报