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页面