0
点赞
收藏
分享

微信扫一扫

Flutter混编(混合开发)

  • 作为独立页面加入
  • 作为原生页面的一部分嵌入(组件)
  • 创建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
举报

相关推荐

0 条评论