一、集成混合开发环境
001 建立flutter_module
% flutter create -t module flutter_module
Creating project flutter_module...
flutter_module/test/widget_test.dart (created)
flutter_module/flutter_module.iml (created)
flutter_module/.gitignore (created)
flutter_module/.metadata (created)
flutter_module/pubspec.yaml (created)
flutter_module/README.md (created)
flutter_module/lib/main.dart (created)
flutter_module/flutter_module_android.iml (created)
flutter_module/.idea/libraries/Dart_SDK.xml (created)
flutter_module/.idea/modules.xml (created)
flutter_module/.idea/workspace.xml (created)
Running "flutter pub get" in flutter_module... 2.7s
Wrote 11 files.
All done!
Your module code is in flutter_module/lib/main.dart.
flutter_module文件下所有文件
flutter_module % ls -al
total 64
drwxr-xr-x 16 staff 512 3 13 10:17 .
drwxr-xr-x 3 staff 96 3 13 10:17 ..
drwxr-xr-x 12 staff 384 3 13 10:17 .android
drwxr-xr-x 3 staff 96 3 13 10:17 .dart_tool
-rw-r--r-- 1 staff 446 3 13 10:17 .gitignore
drwxr-xr-x 5 staff 160 3 13 10:17 .idea
drwxr-xr-x 7 staff 224 3 13 10:17 .ios
-rw-r--r-- 1 staff 309 3 13 10:17 .metadata
-rw-r--r-- 1 staff 3207 3 13 10:17 .packages
-rw-r--r-- 1 staff 325 3 13 10:17 README.md
-rw-r--r-- 1 staff 896 3 13 10:17 flutter_module.iml
-rw-r--r-- 1 staff 1465 3 13 10:17 flutter_module_android.iml
drwxr-xr-x 3 staff 96 3 13 10:17 lib
-rw-r--r-- 1 staff 4079 3 13 10:17 pubspec.lock
-rw-r--r-- 1 staff 3466 3 13 10:17 pubspec.yaml
drwxr-xr-x 3 staff 96 3 13 10:17 test
003 新建一个OC原生项目并放在和fluter_module同一个目录下
004 利用cocoaPods讲flutter 集成到NativeDemo中
关闭bitcode
新建一个Podfile文件便于集成flutter_module
NativeDemo % cat Podfile
platform :ios, '9.0'
use_frameworks!
target 'NativeDemo' do
flutter_application_path = '../flutter_module_2021'
load File.join(flutter_application_path, '.ios', 'Flutter', 'podhelper.rb')
install_all_flutter_pods(flutter_application_path)
end
podhelper.rb
脚本会把你的 plugins, Flutter.framework
,和 App.framework
集成到你的项目中。
二、OC调flutter页面
AppDelegate文件中
//
// AppDelegate.h
// NativeDemo
//
// Created by maochengfang on 2021/3/13.
//
#import <UIKit/UIKit.h>
@import Flutter;
@interface AppDelegate : UIResponder <UIApplicationDelegate>
@property (nonatomic,strong) FlutterEngine *flutterEngine;
@end
//
// AppDelegate.m
// NativeDemo
//
// Created by maochengfang on 2021/3/13.
//
#import "AppDelegate.h"
#import <FlutterPluginRegistrant/GeneratedPluginRegistrant.h>
@interface AppDelegate ()
@end
@implementation AppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// Override point for customization after application launch.
self.flutterEngine = [[FlutterEngine alloc] initWithName:@"my flutter engine"];
// Runs the default Dart entrypoint with a default Flutter route.
[self.flutterEngine run];
// Used to connect plugins (only if you have plugins with iOS platform code).
[GeneratedPluginRegistrant registerWithRegistry:self.flutterEngine];
return YES;
}
#pragma mark - UISceneSession lifecycle
- (UISceneConfiguration *)application:(UIApplication *)application configurationForConnectingSceneSession:(UISceneSession *)connectingSceneSession options:(UISceneConnectionOptions *)options {
// Called when a new scene session is being created.
// Use this method to select a configuration to create the new scene with.
return [[UISceneConfiguration alloc] initWithName:@"Default Configuration" sessionRole:connectingSceneSession.role];
}
- (void)application:(UIApplication *)application didDiscardSceneSessions:(NSSet<UISceneSession *> *)sceneSessions {
// Called when the user discards a scene session.
// If any sessions were discarded while the application was not running, this will be called shortly after application:didFinishLaunchingWithOptions.
// Use this method to release any resources that were specific to the discarded scenes, as they will not return.
}
@end
ViewController中
//
// ViewController.m
// NativeDemo
//
// Created by maochengfang on 2021/3/13.
//
#import "ViewController.h"
#import <Flutter/Flutter.h>
#import "AppDelegate.h"
@interface ViewController ()
@property (nonatomic,strong) FlutterEngine *flutterEngine;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
// Make a button to call the showFlutter function when pressed.
UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
[button addTarget:self
action:@selector(showFlutter)
forControlEvents:UIControlEventTouchUpInside];
[button setTitle:@"Show Flutter!" forState:UIControlStateNormal];
button.backgroundColor = UIColor.blueColor;
button.frame = CGRectMake(80.0, 210.0, 160.0, 40.0);
[self.view addSubview:button];
}
- (void)showFlutter {
FlutterEngine *flutterEngine =
((AppDelegate *)UIApplication.sharedApplication.delegate).flutterEngine;
FlutterViewController *flutterViewController =
[[FlutterViewController alloc] initWithEngine:flutterEngine nibName:nil bundle:nil];
[self presentViewController:flutterViewController animated:YES completion:nil];
}
@end
三、flutter给OC发送消息
fluttr代码
import 'package:flutter/material.dart';
import 'dart:ui';
import 'package:flutter/services.dart';
import 'package:vector_math/vector_math_64.dart';
void main() => runApp(MyApp(pageIndex: window.defaultRouteName,));
class MyApp extends StatefulWidget {
final String pageIndex;
MyApp({Key key,this.pageIndex}) : super(key: key);
@override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
final MethodChannel _oneChannel = MethodChannel('one_page');
final MethodChannel _twoChannel = MethodChannel('two_page');
final BasicMessageChannel _messageChannel = BasicMessageChannel('messageChannel', StandardMessageCodec());
String _pageIndex = 'one';
@override
void initState() {
// TODO: implement initState
super.initState();
_messageChannel.setMessageHandler((message) {
print('收到来自IOS的:$message');
});
_oneChannel.setMethodCallHandler((MethodCall call){
_pageIndex = call.method;
print('收到来自IOS的:$_pageIndex');
setState(() {
});
});
_twoChannel.setMethodCallHandler((MethodCall call) {
_pageIndex = call.method;
print('收到来自IOS的:$_pageIndex');
setState(() {
});
});
}
@override
Widget build(BuildContext context) {
return Container(
child: MaterialApp(
title: 'Flutter Page-Oliver',
theme: ThemeData(
// primaryColor: Colors.greenAccent
),
home: rootPage(_pageIndex),
),
);
}
Widget rootPage(String index){
switch(index){
case 'one':
return Scaffold(
body: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
GestureDetector(
onTap: (){
_oneChannel.invokeMethod('exit','arg');
},
child: Container(
width: 100,
height: 50,
// color: Colors.red,
child: Text('one'),
),
),
TextField(
onChanged: (String str){
_messageChannel.send(str);
},),
],
),
);
break;
case 'two':
return Center(
child: GestureDetector(
onTap: (){
_twoChannel.invokeMethod('exit','arg');
},
child: Container(
width: 100,
height: 100,
child: Text('Two',style: TextStyle(fontSize: 20),),
// color: Colors.blue,
),
),
);
break;
}
}
}
OC代码
- (void)showFlutterOne {
FlutterMethodChannel * methodChannel = [FlutterMethodChannel methodChannelWithName:@"one_page" binaryMessenger:self.vc];
//监听退出
[methodChannel invokeMethod:@"one" arguments:nil];
[methodChannel setMethodCallHandler:^(FlutterMethodCall * _Nonnull call, FlutterResult _Nonnull result) {
if ([call.method isEqualToString:@"exit"]) {
[self.vc dismissViewControllerAnimated:NO completion:nil];
}
}];
// FlutterViewController *flutterViewController =
// [[FlutterViewController alloc] initWithEngine:flutterEngine nibName:nil bundle:nil];
[self presentViewController:self.vc animated:YES completion:nil];
}
四、总结
混合开发实质上就是通过一个桥接的模式进行数据交互
flutter和OC原生之间定义好方法通道 定义好对应的Key和参数
flutter需要定义好MethodChannel
final MethodChannel _oneChannel = MethodChannel('one_page');
flutter MethodChannel 渠道传递给OC的参数,final MethodChannel _oneChannel = MethodChannel('one_page'); _oneChannel.invokeMethod('exit','arg');OC也要定义好FlutterMethodChannel 变量所代表的那个key 监听flutter传过来的Key做一些操作setMethodCallHandler
示例图1: