最近我们客户端的每周技术分享,又轮到我了,记得上次分享了《探索响应式编程及在Android 中的应用》,随着 team
人数不断的增加,分享的周期也变长了呢。
为什么要分享这个主题呢,因为之前有人分享过《Flutter简介及相关文档参考》和《Flutter实现原理》,这两篇的大体内容:Flutter的原理及美团的实践。我看了看就想“入门有了,原理也有了,就差相关实践了”,实践当然是要突出跨平台特性,于是这篇文章就出来了。
一. Flutter 环境配置
首先,在正经开始这篇文章之前先来配置 Flutter
环境。这个和配置 java
环境差不多,先要到 Flutter
中文网 获取Flutter SDK 如下图:
可以按照
Flutter
中文网进行配置, 点击相应的操作系统:
其实,我感觉上面写的太啰嗦了,就是把刚才下载的
Flutter SDK:flutter_macos_v1.2.1-stable.zip
,解压缩,找一个文件夹放进去,之后打开命令行,使用如下命令打开进入编辑模式:
vim ~/.bash_profile
在下面加一行,如下:
export PATH=/sdk/flutter/bin:$PATH
记住,这里要换成你sdk放在本地的地址,我这里放到了根目录下的 sdk
文件夹。
保存:'按住 esc + shift + : ' 之后输入wq:保存并推出
保存好之后运行命令行,使之生效。
source ~/.bash_profile
这个时候应该能运行 Flutter
命令了,我们运行命令行:
flutter -h
如下图所示:
二. 混合开发方案选择
目前的主流混合开发方案有两种集成方式:
源码集成:也就是谷歌官方提供的方案。
产物集成: Flutter
项目单独开发,开发完成后发布成 aar
包或者 IOS
的 framework
形式,原生项目依赖 Flutter
输出的制品即可。
两种方式各有优劣,其实产物集成更好一些,不过即使是进行产物集成,也需要弄懂源码集成的方式,因为当有很多和原生交互的功能进行开发的时候,源码集成的方式可以直接调试会方便很多。
所以,本文主要围绕源码集成方式,产物集成见另外一篇: Flutter与Android混合开发之产物集成
三. 为 Flutter 原生项目集成Flutter
整个的集成方案是参考谷歌方法。
1.创建flutter module project
我们假定已经有了原生的项目 Native-iOS
和 Native-Android
;现在我们需要创建我们的 Flutter
项目。由于咱们上边已经配置好了 Flutter
环境,运行命令:
flutter create -t module {moduleName}
如下图所示:
这里我的项目名称为
flutter_app
。
2. 创建 Flutter 模块的项目
进到项目 flutter_app
根目录,还是上面那个命令,这里我创建了一个 Flutter
的模块项目叫 flutter_module
。
在 Flutter
的模块项目中包含有一个隐藏的 .android
和 .ios
目录这个目录下是可运行的 Android
和 iOS
项目,我们的 Flutter
代码还是在 lib
下编写,注意在 .android
和 .ios
目录下都有一个 Flutter
目录,这个是我们 Flutter
的库项目了。也就是 Android
用来生成 aar
, IOS
用来生产 framework
的库。如果我们用 flutter create xxx
生成的纯 Flutter
项目是没有这个 Flutter
目录的。
注:把项目 `flutter_module` 使用 `git` 管理起来,
这样我们在 `native` 项目中以子模块添加就不用复制粘贴了,也方便团队人员协同开发。
自己开发的时候直接拷贝就好了哈。
四. 给 IOS 项目集成 Flutter
1. 进入我们原生的 IOS 项目根目录中,为它添加一个 git submodule,把我们的 Flutter 项目拉取下来。
git submodule add {你的flutter module的仓库地址}
git submodule update
2.在项目的 Podfile 文件中添加下面的代码,在每次执行 pod install 会运行 podhelper.rb
注:iOS开发中,新创建一个项目的时候,项目总目录里面没有pods的配置文件,
实际上电脑上面是安装的有cocoapods的。
1. 打开电脑终端,然后cd到项目总路径下,输入:pod init,创建podfile的配置文件,如下图所示:
代码如下:
...
end
#fluter module
#添加如下两行代码,路径修改为我们的fluter module的路径���
flutter_application_path = '/Users/randy/WebstormProject/myapp/flutter_module'
eval(File.read(File.join(flutter_application_path, '.ios', 'Flutter', 'podhelper.rb')), binding)
#注意,注意,一定要注意路径是否正确!!!
3. 打开 Xcode 关闭 bitcode 配置 Build Settings->Build Options->Enable Bitcode
可能对于只做 Android
开发的人员不够详细,那就见下图:
4. 添加编译脚本,打开 Xcode 在 Build Phases 中添加 New Run Script Phase 在里面填入如下脚本
"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh" build
"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh" embed
5. 项目的配置完成现在需要生成一些配置文件
a. 进入 IOS
原生项目的 Flutter
模块目录中执行 flutter packages get
命令。
b. 回到原生项目根目录执行 pod install
。
到此为止我们的原生项目就已经集成好了 Flutter
项目了。
6. 在原生项目中使用 Flutter,下面以 swift 项目为例
修改 AppDelegate.swift
注意 AppDelegate
是集成自 FlutterAppDelegate
import UIKit
import Flutter
import FlutterPluginRegistrant
@UIApplicationMain
class AppDelegate: FlutterAppDelegate {
var flutterEngine : FlutterEngine?;
override func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
self.flutterEngine = FlutterEngine(name: "io.flutter", project: nil);
self.flutterEngine?.run(withEntrypoint: nil);
GeneratedPluginRegistrant.register(with: self.flutterEngine);
return super.application(application, didFinishLaunchingWithOptions: launchOptions);
}
}
修改 Controller
代码
import UIKit
import Flutter
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
// let button = UIButton(type:UIButtonType.custom)
// self.view.addSubview(button)
}
@objc func handleButtonAction() {
let flutterEngine = (UIApplication.shared.delegate as? AppDelegate)?.flutterEngine;
let flutterViewController = FlutterViewController(engine: flutterEngine, nibName: nil, bundle: nil)!;
self.present(flutterViewController, animated: true, completion: nil)
}
// 这里我改成了直接点击屏幕跳转
override func touchesBegan(_ touches: Set, with event: UIEvent?) {
handleButtonAction();
}
}
最后,RUN
就好了!
运行程序的时候在 Build phase
添加了 xcode_backend.sh
该脚本会使用到上面 pod install
给 xcode build setting
设置的那些环境变量,然后找到项目目录生成 AppFramework
。
五. 给原生 Android 项目集成 Flutter
1. 在原生 Android 项目中添加子模块,将上面创建的 flutter module 项目拉取到原生安卓项目中
git submodule add {你的flutter module的仓库地址}
git submodule update
2.在根目录的 settings.gradle 中添加如下配置
include ':app'
setBinding(new Binding([gradle: this]))
evaluate(new File(
'{xxxxx你的flutter module目录}/.android/include_flutter.groovy'
))
3.在原生项目的 app 目录下的 build.gradle 文件中添加 Flutter 库的依赖
dependencies {
implementation project(':flutter')
}
4.在原生代码中集成 Flutter 跳转到 Flutter 页面
我使用了一个新的 Activity
进行跳转。具体可以参看源码
/**
* @author randy
*/
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button open = findViewById(R.id.btn_jump);
open.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent();
intent.setClass(MainActivity.this, MyFlutterActivity.class);
startActivity(intent);
}
});
}
}
public class MyFlutterActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_flutter);
final FlutterView flutterView = Flutter.createView(
this,
getLifecycle(),
"route1"
);
final FrameLayout layout = findViewById(R.id.flutter_container);
layout.addView(flutterView);
final FlutterView.FirstFrameListener[] listeners = new FlutterView.FirstFrameListener[1];
listeners[0] = new FlutterView.FirstFrameListener() {
@Override
public void onFirstFrame() {
layout.setVisibility(View.VISIBLE);
}
};
flutterView.addFirstFrameListener(listeners[0]);
}
}
Android
从原生跳到 Flutter
模块的黑屏问题,在网上看到很多说设置透明主题的但是没有用,后来看到一种先隐藏显示,等待渲染好第一帧后才显示 Flutter
页面的方法。这里要注意一点要在布局中先把 Flutter
的 Container
布局设置为 InVisible
状态,不要使用 Gone
,用 Gone
的话是不显示也不渲染,用 InVisible
不显示但是会渲染界面占位置,等待渲染完成后再设置为 Visible
即可。
项目 demo
,我已经上传到百度网盘,地址
最后:
这是整个项目用来开发的示意图:
我们整个项目都是使用
git
进行管理的,虽然每个开发者都需要安装
Flutter
环境,但是对于小团队来说成本并不高,加上
flutter_wrapper
也保证了版本的一致性。
IOS
开发者可以在原来的
IOS
项目中开发
Flutter
的项目,
Android
开发者可以在原
Android
项目中开发
Flutter
,
Flutter
开发者也可以自己单独开发
Flutter
项目,这种方式其实对于开发者来说也是很方便的。
参考链接
以上大部分都是参考炸鸡叔的文章原生App项目集成flutter混合开发详细指南。
而我仿佛是站在巨人身上,但是项目是我一步一步按照上面的步骤来的,我是一个搞 Android
的,遇到 IOS
代码也是感觉挺茫然的。
最后的最后:
开发 Flutter
的 IDE
我没有用 Android Studio
,而是选择的 WebStorm
,这个看个人爱好和便利性吧,也许在某天我就会选择 VS Code
。在这里记一下我常用的命令行:
查看连接的设备 adb devices (但是不知道为何看不到ios设备,可能需要真机连接吧)
打开ios虚拟机 open -a Simulator
运行项目 flutter run