跳转至

混合开发与引擎

Flutter项目调用原生的功能(相机,相册)

通讯

MethodChannel

主要传递方法调用,一次通讯

methodChannel调用invokeMethod:发送消息

methodChannel调用setMethodCallHandler:设置回调

flutter

import 'dart:io';

import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_demo/widgets/scaffold_demo.dart';

class MethodChannelDemo extends StatefulWidget {
  const MethodChannelDemo({Key? key}) : super(key: key);

  @override
  State<MethodChannelDemo> createState() => _MethodChannelDemoState();
}

class _MethodChannelDemoState extends State<MethodChannelDemo> {
  File? _avatarFile;
  final MethodChannel _methodChannel = const MethodChannel('mine_page/method');

  @override
  void initState() {
    // TODO: implement initState
    super.initState();
    _methodChannel.setMethodCallHandler((call) {
      if (call.method == 'imagePath') {
        print(call.arguments);
        String imagePath = call.arguments.toString().substring(7);
        setState(() {
          _avatarFile = File(imagePath);
        });
      }
      return Future(() {});
    });
  }

  @override
  Widget build(BuildContext context) {
    return HHScaffold(
      Center(
        child: //头像
            GestureDetector(
          onTap: () {
            _methodChannel.invokeMapMethod('picture'); //通知原生
          },
          child: Container(
            width: 70,
            height: 70,
            //圆角
            decoration: BoxDecoration(
                borderRadius: BorderRadius.circular(12),
                image: DecorationImage(
                    image: _avatarFile == null
                        ? const AssetImage('images/Hank.png') as ImageProvider
                        : FileImage(_avatarFile!),
                    //裁剪
                    fit: BoxFit.cover)),
          ),
        ),
      ),
      title: 'channel',
    );
  }
}

iOS

#import <Flutter/Flutter.h>
#import <UIKit/UIKit.h>

@interface AppDelegate : FlutterAppDelegate<UINavigationControllerDelegate,UIImagePickerControllerDelegate>
@property (nonatomic, strong)FlutterMethodChannel *methodChannel;
@end
#import "AppDelegate.h"
#import "GeneratedPluginRegistrant.h"

@implementation AppDelegate

- (BOOL)application:(UIApplication *)application
didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    [GeneratedPluginRegistrant registerWithRegistry:self];

    //注册方法 flutter和原生交互
    FlutterViewController *vc = (FlutterViewController *)self.window.rootViewController;
    self.methodChannel = [FlutterMethodChannel methodChannelWithName:@"mine_page/method" binaryMessenger:vc];
    UIImagePickerController *imageVC = [[UIImagePickerController alloc]init];
    imageVC.delegate = self;
    [self.methodChannel setMethodCallHandler:^(FlutterMethodCall * _Nonnull call, FlutterResult  _Nonnull result) {
        if ([call.method isEqualToString:@"picture"]) {
            [vc presentViewController:imageVC animated:YES completion:nil];
        }
    }];

    // Override point for customization after application launch.
    return [super application:application didFinishLaunchingWithOptions:launchOptions];
}

- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary<UIImagePickerControllerInfoKey,id> *)info {
    [picker dismissViewControllerAnimated:YES completion:^{
        NSString *imagePath = [NSString stringWithFormat:@"%@",info[@"UIImagePickerControllerImageURL"]];
        [self.methodChannel invokeMethod:@"imagePath" arguments:imagePath];
    }];
}

@end

BasicMessageChannel

持续通讯,收到消息之后还可以回复消息。

EventChannel

数据流 持续通讯

创建:Channel构造方法有name,

发:invoke方法名,

接收回调:setMethodCallHandler,setMessageHandler

混合工程自动化

工程自动化重点是写脚本。

flutter工程,iOS工程,android工程。不需要配置环境。

混合工程一般单独的工程,flutter是module,iOS也有一个native工程。

混合开发 原生项目嵌入Flutter

AS创建Flutter Module

.android.ios是隐藏文件,调试用的,里面不要写代码,不会打包进去。

1、原生有flutter环境

比较重,不建议。有渲染引擎Flutter.framework也要进内存。

iOS没有flutter,需要使用pod。

Xcode创建工程,pod init创建pod。

#flutter插件路径
flutter_application_path = '../flutter_module' 
# 加载函数 参数1:flutter路径 2:iOS 3:这是flutter工程 4:podhelper.rb
load File.join(flutter_application_path,'.iOS','Flutter','podhelper.rb')

platform :ios, '9.0'

target 'NativeDemo' do
  # 安装
  install_all_flutter_pods(flutter_application_path)#flutter依赖的库也加载进来
  use_frameworks!

  # Pods for NativeDemo

end

pod install之后,native就有了flutter的东西了。

修改了flutter代码,AS编译或者Xcode清空缓存运行。

2、原生没有flutter环境

2.1 framework混合开发

打包成framework直接给native使用。

  1. 终端进入flutter module目录

  2. flutter build ios-framework --output=../flutter_app

构建混合工程

  1. Debug调试
  2. Profile介于发布和调试,既有release性能,又有debug的调试功能。
  3. Release发布

Flutter.xcframework和flutter环境有关。

App.xcframework和自己写的flutter代码页面有关。

多个flutter module只需要一个Flutter.xcframework,和不同的App.xcframework

  1. 集成framework

image-20220508201742864

2.2 cocoapods混合工程

  1. 终端进入flutter module目录

  2. flutter build ios-framework --cocoapods --output=../flutter_app

构建混合工程

  1. Debug调试
  2. Profile介于发布和调试,既有release性能,又有debug的调试功能。
  3. Release发布

Flutter.podspec和flutter环境有关,从cocoapods上下载。

App.xcframework和自己写的flutter代码页面有关。

多个flutter module只需要一个Flutter.xcframework,和不同的App.xcframework

  1. 把文件拖进native工程

  2. 创建podfile,添加pod 'Flutter',:podspec => 'Debug/Flutter.podspec',然后pod install。

  3. 配置App.xcframework

flutter只要做了更改,原生就需要更新,需要一个代码仓库,flutter把module开发完之后,代码push,仓库把代码工程打包编译成native使用的framework。

借用GitHub,Actions自己写脚本代码CI就可以实现上面的功能。

引擎

下载引擎:https://github.com/flutter/engine

路径不要有中文

三方工作所在目录需要有可执行权限

flutter版本:

  ~ flutter channel 
Flutter channels:
  master//主分支
  dev       //正在开发
  beta  //新特性
* stable//稳定版
➜  ~ 

编译引擎

GN构建文件

  1. 进入路径路径/engine_download/src/flutter/tools
# iOS
# 真机debug
./gn --ios --unoptimized
# 真机release ( , ) 
./gn --ios --unoptimized --runtime-mode=release 
# 模拟器版本
./gn --ios --simulator --unoptimized
# 主机端(Mac)构建
./gn --unoptimized

Ninja编译

  1. 先安装ant:brew install ant

  2. 进入路径路径/engine_download/src/out

  3. bash ninja -C host_debug_unopt && ninja -C ios_debug_sim_unopt && ninja -C ios_debug_unopt && ninja -C ios_release_unopt