目前大多数公司都有本身开发多年的项目,不可能直接用
Flutter
从头开发一套,那样不实现,除非是小项目,所以只能是在原有的基础上用Flutter
来开发新业务或重构旧业务,而这里就须要用到Flutter
的混合开发
java
使用混合开发就不能像以前同样直接上来就建立一个 Flutter
项目,而是要使用 Flutter模板
android
# flutter_module_lxf 能够随便你命名
flutter create --template module flutter_module_lxf
# --template 能够替换为 -t
# flutter create -t module flutter_module_lxf
复制代码
建立出来的 Flutter
模块依然是能够像以前建立的Flutter项目
同样打开和运行的。ios
目录下有也有 ios
和 android
目录,只不过前面加了个点 ,成了点目录。git
经过
Cocoapods
,将Flutter
模块编译成一个库,再到原生项目中进行引入和使用便可github
在 Podfile
中添加两行配置shell
# 指定咱们刚刚建立的 Flutter 模块的路径
flutter_application_path = '../flutter_module_lxf'
# 拼接脚本文件的路径: .ios/Flutter/podhelper.rb
load File.join(flutter_application_path, '.ios', 'Flutter', 'podhelper.rb')
复制代码
在每一个须要引用 Flutter
的 Target
下,都须要添加一行配置swift
install_all_flutter_pods(flutter_application_path)
复制代码
添加后以下所示:api
flutter_application_path = '../flutter_module_lxf'
load File.join(flutter_application_path, '.ios', 'Flutter', 'podhelper.rb')
use_frameworks!
target 'LXFFlutterHybridDemo' do
install_all_flutter_pods(flutter_application_path)
end
复制代码
添加完成后,执行一次 pod install
ruby
两个步骤bash
- 获取 Flutter引擎
FlutterEngine
- 经过
FlutterEngine
建立FlutterViewController
AppDelegate
类中声明一个 FlutterEngine
变量,在 didFinishLaunchingWithOptions
方法中启动 Flutter引擎
// AppDelegate.swift
import Flutter
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
// 建立 Flutter引擎
lazy var flutterEngine = FlutterEngine(name: "lxf")
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
// 启动 Flutter引擎
flutterEngine.run()
return true
}
...
}
复制代码
ViewController
中添加一个按钮,点击弹出 Flutter模块
// ViewController.swift
override func viewDidLoad() {
super.viewDidLoad()
let btn = UIButton(type: .custom)
btn.frame = CGRect(x: 100, y: 200, width: 200, height: 44)
btn.backgroundColor = .black
btn.addTarget(self, action: #selector(showFlutterVc), for: .touchUpInside)
btn.setTitle("弹出Flutter模块", for: .normal)
self.view.addSubview(btn)
}
@objc func showFlutterVc() {
// 建立FlutterViewController
let flutterVc = FlutterViewController(engine: fetchFlutterEngine(), nibName: nil, bundle: nil)
self.present(flutterVc, animated: true, completion: nil)
}
func fetchFlutterEngine() -> FlutterEngine {
return (UIApplication.shared.delegate as! AppDelegate).flutterEngine
}
复制代码
若是遇到报 Command PhaseScriptExecution failed with a nonzero exit code
错误,以下图所示:
请先用 Android Studio
或 VSCode
打开 Flutter模块
项目并运行到iOS设备上,让其帮咱们对iOS项目进行一些初始化配置。成功运行后就能够关闭 Flutter模块
项目的运行了,接着再用 Xcode
打开原生项目运行便可。
官方文档里面提到,修改初始路由,须要在 Flutter引擎
在 run
以前,经过 invokeMethod
调用 setInitialRoute
方法进行设置,代码以下
// 修改初始路由
flutterEngine.navigationChannel.invokeMethod("setInitialRoute", arguments: "/other")
// 启动 Flutter引擎
flutterEngine.run()
复制代码
可是,我发现这样写并无起任何做用,在 Flutter
的官方 issue
上也有人提到这个问题: 【setInitialRoute is broken for iOS add-to-app #59895】,目前只能官方进行修复和调整 API
临时可使用以下方式实现:
let flutterVc = FlutterViewController(project: FlutterDartProject(), nibName: nil, bundle: nil)
flutterVc.setInitialRoute("/other")
self.present(flutterVc, animated: true, completion: nil)
复制代码
虽然这么写能够实现这个功能,可是会有明显的相似卡顿的现象,由于使用这种方式去建立 FlutterViewController
以前,会隐式建立和启动一个 FlutterEngine
,而咱们弹出 FlutterViewController
时 FlutterEngine
还没加载完毕,因此咱们会看到先弹出了一个透明的界面,再显示 /other
路由对应的界面视图。
使用 FlutterAppDelegate
这个不是必要的操做,可是若是你想让 Flutter模块
也能使用原生的功能的话,建议使用
原生功能
- 处理
openURL
的回调- 列表视图在点击状态栏后滚到顶部
class AppDelegate: FlutterAppDelegate 复制代码
更具体的使用,请阅读 官方文档
修改安卓项目 根目录下的 settings.gradle
文件
// settings.gradle
include ':app' // assumed existing content
setBinding(new Binding([gradle: this])) // new
evaluate(new File( // new
settingsDir.parentFile, // new
// 这里的 flutter_module_lxf 请修改成你本身建立的Flutter模板目录名称
'flutter_module_lxf/.android/include_flutter.groovy' // new
))
复制代码
修改安卓项目 app
目录下的 build.gradle
文件
// app/build.gradle
dependencies {
...
// 配置flutter依赖
implementation project(':flutter')
}
复制代码
若是在编译的时候遇到以下错误
Default interface methods are only supported starting with Android N (--min-api 24): void androidx.lifecycle.DefaultLifecycleObserver.onCreate(androidx.lifecycle.LifecycleOwner)
复制代码
请确认是否指定了使用 Java 8
进行编译 【官方文档 - Java 8 requirement】
修改安卓项目 app
目录下的 build.gradle
文件
// app/build.gradle
android {
...
compileOptions {
sourceCompatibility 1.8
targetCompatibility 1.8
}
...
}
复制代码
修改 app/src/main/AndroidManifest.xml
文件
// app/src/main/AndroidManifest.xml
<activity android:name="io.flutter.embedding.android.FlutterActivity" android:theme="@style/AppTheme" android:configChanges="orientation|keyboardHidden|keyboard|screenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode" android:hardwareAccelerated="true" android:windowSoftInputMode="adjustResize" />
复制代码
添加一个按钮,点击弹出 Flutter模块
<!-- activity_main.xml -->
<Button android:id="@+id/btn" android:layout_width="wrap_content" android:layout_height="wrap_content" android:textSize="20sp" android:text="弹出Flutter模块" android:background="#000000" android:textColor="#ffffff" android:gravity="center" android:onClick="btnClick" />
复制代码
// MainActivity.java
public void btnClick(View v) {
startActivity(
FlutterActivity.createDefaultIntent(this)
);
}
复制代码
因为当前咱们是使用原生开发工具(如:Xcode)来运行项目,每次修改咱们的
Flutter模块
的代码,也就须要从新运行才能看到效果,不像以前按下Cmd + s
就能进行热重载。这样Flutter模块
的开发效率极其低下,那有没有办法可让咱们像以前开发Flutter
项目时那样进行热重载
呢?答案是有的
Flutter
官方提供了 flutter attach
,以辅助咱们开发,到终端下执行
flutter attach
复制代码
若是当前有多个设备,会提示咱们须要指定 attach
哪一个设备
按要求加上指定参数便可
flutter attach -d FE305309-9E79-418D-BA3F-7EFECF2980BC
复制代码
如图,这样就关联上了,你在 dart
文件里面对界面进行任何修改后,按 r
进行热重载,按 R
进行热启动。
若是你使用的是 Android Studio
,能够直接选择对应的设备后,点击右边的 Flutter Attach
按钮,执行成功后就能够跟以前同样按 Cmd + s
进行热重载了。
GitHub
官方文档
add-to-app | add-to-app/ios | add-to-app/android | Debugging & hot reload