- 作为独立页面加入
- 作为原生页面的一部分嵌入(组件)
- 创建Flutter module
- 添加Flutter module 依赖
- 在Java/Object-C调用Flutter module
- 编写Dart代码
- 运行项目
- 热重启/热重载
- 调试Dart代码
- 发布应用
一、原生显示Flutter页面
①.Flutter环境配置
打开AndroidStudio,选择Flutter Module
终端创建Flutter Module
flutter create -t module xxx
②.iOS配置
1.添加Podfile
文件
platform :ios, '9.0'
use_frameworks!
target 'NativeDemo' do
flutter_application_path = '../flutter_module/'
eval(File.read(File.join(flutter_application_path, '.ios', 'Flutter', 'podhelper.rb')), binding)
end
2.去掉bitcode
3.使用脚本
"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh" build
"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh" embed
编译成功即可~
③跳转Flutter页面
#import "ViewController.h"
///引入Flutter头文件
#import <Flutter/Flutter.h>
@interface ViewController ()
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
}
///显示Flutter页面
- (IBAction)showFlutterPage:(id)sender {
FlutterViewController * flutterViewController = [[FlutterViewController alloc] init];
[self presentViewController:flutterViewController animated:YES completion:nil];
}
@end
二、显示不同页面
1.通过setInitialRoute
向Flutter传入参数
FlutterViewController * flutterViewController = [[FlutterViewController alloc] init];
[flutterViewController setInitialRoute:@"two"];
[self presentViewController:flutterViewController animated:YES completion:nil];
2.Flutter接收传入参数并显示不同内容
//window.defaultRouteName 原生传入的RouteName
import 'package:flutter/material.dart';
import 'dart:ui';
void main() => runApp(MyApp(pageIndex:window.defaultRouteName));
class MyApp extends StatelessWidget {
final String pageIndex;
const MyApp({Key key, this.pageIndex}) : super(key: key);
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: rootPage(pageIndex),
);
}
}
Widget rootPage(String pageIndex){
switch (pageIndex){
case 'one' :
return Center(child: Text('One'),);
case 'two' :
return Center(child: Text('Two'),);
default:
return Center(child: Text('Default'),);
}
}
三、Flutter和原生通讯
①Flutter代码
import 'package:flutter/material.dart';
import 'dart:ui';
import 'package:flutter/services.dart';
void main() => runApp(MyApp(pageIndex: window.defaultRouteName));
class MyApp extends StatefulWidget {
final String pageIndex;
const 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');
String _pageIndex = 'one';
@override
void initState() {
// TODO: implement initState
super.initState();
_oneChannel.setMethodCallHandler((MethodCall call) {
_pageIndex = call.method;
setState(() {});
});
_twoChannel.setMethodCallHandler((MethodCall call) {
_pageIndex = call.method;
setState(() {});
});
}
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: rootPage(_pageIndex),
);
}
Widget rootPage(String pageIndex) {
switch (pageIndex) {
case 'one':
return GestureDetector(
onTap: () {
_oneChannel.invokeMethod('exit', 'arguments'); //名字是唯一标识,发送退出标识
},
child: Container(
width: 50,
height: 50,
color: Colors.red,
child: Center(
child: Text('One'),
),
),
);
case 'two':
return GestureDetector(
onTap: () {
_twoChannel.invokeMethod('exit', 'arguments'); //名字是唯一标识,发送退出标识
},
child: Container(
width: 50,
height: 50,
color: Colors.blue,
child: Center(
child: Text('Two'),
),
),
);
default:
return GestureDetector(
child: Container(
width: 50,
height: 50,
color: Colors.grey,
child: Center(
child: Text('Default'),
),
),
);
}
}
}
②原生代码
#import "ViewController.h"
#import <Flutter/Flutter.h>
@interface ViewController ()
/** flutterViewController */
@property (nonatomic, strong) FlutterViewController * flutterViewController ;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
self.flutterViewController = [[FlutterViewController alloc] init];
FlutterMethodChannel * methodChannel = [FlutterMethodChannel methodChannelWithName:@"one_page" binaryMessenger:self.flutterViewController];
[methodChannel setMethodCallHandler:^(FlutterMethodCall * _Nonnull call, FlutterResult _Nonnull result) {
NSLog(@"call:%@--arguments:%@",call.method,call.arguments);
if ([call.method isEqualToString:@"exit"]) {
[self.flutterViewController dismissViewControllerAnimated:YES completion:nil];
}
}];
}
///显示Flutter页面
- (IBAction)showFlutterPage:(id)sender {
FlutterMethodChannel * methodChannel = [FlutterMethodChannel methodChannelWithName:@"one_page" binaryMessenger:self.flutterViewController];
[methodChannel invokeMethod:@"one" arguments:nil];
[methodChannel setMethodCallHandler:^(FlutterMethodCall * _Nonnull call, FlutterResult _Nonnull result) {
NSLog(@"call:%@--arguments:%@",call.method,call.arguments);
if ([call.method isEqualToString:@"exit"]) {
[self.flutterViewController dismissViewControllerAnimated:YES completion:nil];
}
}];
[self presentViewController:self.flutterViewController animated:YES completion:nil];
}
- (IBAction)showFlutterPageTwo:(id)sender {
NSLog(@"aasds");
FlutterMethodChannel * methodChannel = [FlutterMethodChannel methodChannelWithName:@"two_page" binaryMessenger:self.flutterViewController];
[methodChannel invokeMethod:@"two" arguments:nil];
[methodChannel setMethodCallHandler:^(FlutterMethodCall * _Nonnull call, FlutterResult _Nonnull result) {
NSLog(@"call:%@--arguments:%@",call.method,call.arguments);
if ([call.method isEqualToString:@"exit"]) {
[self.flutterViewController dismissViewControllerAnimated:YES completion:nil];
}
}];
[self presentViewController:self.flutterViewController animated:YES completion:nil];
}
@end
四、原生通讯和Flutter通讯
Channel
- MethodChannel 传递方法 一次通讯
- BasicMessageChannel 传递字符串
- EventChannel 传递数据流
①BasicMessageChannel 监听输入框输入文本 持续传输
Flutter代码
final BasicMessageChannel _messageChannel = BasicMessageChannel('messageChannel',StandardMessageCodec());
@override
void initState() {
// TODO: implement initState
super.initState();
_messageChannel.setMessageHandler((message){
print('收到了来自于iOS的:$message');
});
}
TextField(
onChanged: (String msg) {
_messageChannel.send(msg);
},
)
原生代码
#import "ViewController.h"
#import <Flutter/Flutter.h>
@interface ViewController ()
/** flutterViewController */
@property (nonatomic, strong) FlutterViewController * flutterViewController ;
@property (nonatomic, strong) FlutterBasicMessageChannel *massageChannel ;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
self.flutterViewController = [[FlutterViewController alloc] init];
[self.flutterViewController setInitialRoute:@"one"];
//监听MessageChannel的数据
self.massageChannel = [FlutterBasicMessageChannel messageChannelWithName:@"messageChannel" binaryMessenger:self.flutterViewController];
[self.massageChannel setMessageHandler:^(id _Nullable message, FlutterReply _Nonnull callback) {
NSLog(@"接收来自Flutter的消息: %@",message);
}];
}
///显示Flutter页面
- (IBAction)showFlutterPage:(id)sender {
FlutterMethodChannel * methodChannel = [FlutterMethodChannel methodChannelWithName:@"one_page" binaryMessenger:self.flutterViewController];
[methodChannel invokeMethod:@"one" arguments:nil];
[methodChannel setMethodCallHandler:^(FlutterMethodCall * _Nonnull call, FlutterResult _Nonnull result) {
NSLog(@"call:%@--arguments:%@",call.method,call.arguments);
if ([call.method isEqualToString:@"exit"]) {
[self.flutterViewController dismissViewControllerAnimated:YES completion:nil];
}
}];
[self presentViewController:self.flutterViewController animated:YES completion:nil];
}
- (IBAction)showFlutterPageTwo:(id)sender {
NSLog(@"aasds");
FlutterMethodChannel * methodChannel = [FlutterMethodChannel methodChannelWithName:@"two_page" binaryMessenger:self.flutterViewController];
[methodChannel invokeMethod:@"two" arguments:nil];
[methodChannel setMethodCallHandler:^(FlutterMethodCall * _Nonnull call, FlutterResult _Nonnull result) {
NSLog(@"call:%@--arguments:%@",call.method,call.arguments);
if ([call.method isEqualToString:@"exit"]) {
[self.flutterViewController dismissViewControllerAnimated:YES completion:nil];
}
}];
[self presentViewController:self.flutterViewController animated:YES completion:nil];
}
-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
//向Flutter发送消息
static int a = 0;
[self.massageChannel sendMessage:[NSString stringWithFormat:@"iOS来了===%d",a++]];
}
@end
⑤Flutter 调起原生相册页面
Flutter部分
class _MyAppState extends State<MyApp> {
MethodChannel _methodChannel = MethodChannel('mine_page/method');
@override
void initState() {
// TODO: implement initState
super.initState();
_methodChannel.setMethodCallHandler((MethodCall call){
print(call.arguments);
});
}
@override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: Scaffold(
backgroundColor: Colors.cyanAccent,
body: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
GestureDetector(
onTap: (){
_methodChannel.invokeMethod('picture');
},
child: Container(
margin: EdgeInsets.only(top: 40, right: 10),
height: 25,
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Image(image: AssetImage('images/相机.png')),
],
),
),
),
],
),
),
);
}
}
原生部分
#import "AppDelegate.h"
#import <Flutter/Flutter.h>
@interface AppDelegate ()<UIApplicationDelegate,UINavigationControllerDelegate, UIImagePickerControllerDelegate>
@property (nonatomic, strong) FlutterMethodChannel * methodChannel;
@end
@implementation AppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
FlutterViewController *vc = [[FlutterViewController alloc] init];
self.window.rootViewController = vc;
//显示相册
self.methodChannel = [FlutterMethodChannel methodChannelWithName:@"mine_page/method" binaryMessenger:vc];
UIImagePickerController *imagePicker = [[UIImagePickerController alloc]init];
imagePicker.delegate = self;
[self.methodChannel setMethodCallHandler:^(FlutterMethodCall * _Nonnull call, FlutterResult _Nonnull result) {
if ([call.method isEqualToString:@"picture"]) {
[vc presentViewController:imagePicker animated:YES completion:nil];
}
}];
return YES;
}
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info{
[picker dismissViewControllerAnimated:YES completion:^{
NSString * imageUrl = [NSString stringWithFormat:@"%@",info[@"UIImagePickerControllerImageURL"]];
[self.methodChannel invokeMethod:@"image" arguments:imageUrl];
}];
}
效果图
调试Dart代码
- 关闭APP
- 点击AndroidStudio的
Flutter Attach
按钮 -
启动App
补充
1 Android 发布应用
- 生成Android 签名证书
- 设置gradle变量
- 在grable中配置文件中添加签名配置
- 签名打包APK
./gradlew assembleRelease