使用Flutter從零開始開發App是一件輕鬆愜意的事情,但對於一些成熟的產品來講,徹底摒棄原有App的歷史沉澱,全面轉向Flutter是不現實的。所以使用Flutter去統一Android、iOS技術棧,把它做爲已有原生App的擴展能力,經過有序推動來提高移動終端的開發效率。 目前,想要在已有的原生App裏嵌入一些Flutter頁面主要有兩種方案。一種是將原生工程做爲Flutter工程的子工程,由Flutter進行統一管理,這種模式稱爲統一管理模式。另外一種是將Flutter工程做爲原生工程的子模塊,維持原有的原生工程管理方式不變,這種模式被稱爲三端分離模式。android
默認狀況下,新建立的Flutter工程會包含Flutter目錄和原生工程的目錄。在這種狀況下,原生工程會依賴Flutter工程的庫和資源,而且沒法脫離Flutter工程獨立構建和運行。 在混合開發中,原生工程對Flutter的依賴主要分爲兩部分。一個是Flutter的庫和引擎,主要包含Flutter的Framework 庫和引擎庫;另外一個是Flutter模塊工程,即Flutter混合開發中的Flutter功能模塊,主要包括Flutter工程lib目錄下的Dart代碼實現。 對於原生工程來講,集成Flutter只須要在同級目錄建立一個Flutter模塊,而後構建iOS和Android各自的Flutter依賴庫便可。接下來,咱們只須要在原生項目的同級目錄下,執行Flutter提供的構建模塊命令建立Flutter模塊便可,以下所示。ios
flutter create -t module flutter_library
複製代碼
其中,flutter_library爲Flutter模塊名。執行上面的命令後,會在原生工程的同級目錄下生成一個flutter_library模塊工程。Flutter模塊也是Flutter工程,使用Android Studio打開它,其目錄以下圖所示。 git
在原生Android工程中集成Flutter,原生工程對Flutter的依賴主要包括兩部分,分別是Flutter庫和引擎,以及Flutter工程構建產物。github
和原生Android工程集成其餘插件庫的方式同樣,在原生Android工程中引入Flutter模塊須要先在settings.gradle中添加以下代碼。xcode
setBinding(new Binding([gradle: this]))
evaluate(new File(
settingsDir.parentFile,
'flutter_library/.android/include_flutter.groovy'))
複製代碼
其中,flutter_library爲咱們建立的Flutter模塊。而後,在原生Android工程的app目錄的build.gradle文件中添加以下依賴。bash
dependencies {
implementation project(":flutter")
}
複製代碼
而後編譯並運行原生Android工程,若是沒有任何錯誤則說明集成Flutter模塊成功。須要說明的是,因爲Flutter支持的最低版本爲16,因此須要將Android項目的minSdkVersion修改成16。 若是出現「程序包android.support.annotation不存在」的錯誤,須要使用以下的命令來建立Flutter模塊,由於最新版本的Android默認使用androidx來管理包。app
flutter create --androidx -t module flutter_library
複製代碼
對於Android原生工程,若是尚未升級到androidx,能夠在原生Android工程上右鍵,而後依次選擇【Refactor】→【Migrate to Androidx】將Android工程升級到androidx包管理。 在原生Android工程中成功添加Flutter模塊依賴後,打開原生Android工程,並在應用的入口MainActivity文件中添加以下代碼。框架
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
View flutterView = Flutter.createView(this, getLifecycle(), "route1");
FrameLayout.LayoutParams layoutParams = new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
addContentView(flutterView, layoutParams);
}
}
複製代碼
經過Flutter提供的createView()方法,能夠將Flutter頁面構建成Android可以識別的視圖,而後將這個視圖使用Android提供的addContentView()方法添加到父窗口便可。從新運行原生Android工程,最終效果以下圖所示。 ide
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
FragmentTransaction ft= getSupportFragmentManager().beginTransaction();
ft.replace(R.id.fragment_container, Flutter.createFragment("Hello Flutter"));
ft.commit();
}
}
複製代碼
除了使用Flutter模塊方式集成外,還能夠將Flutter模塊打包成aar,而後再添加依賴。在flutter_library根目錄下執行aar打包構建命令便可抽取Flutter依賴,以下所示。模塊化
flutter build apk --debug
複製代碼
此命令的做用是將Flutter庫和引擎以及工程產物編譯成一個aar包,上面命令編譯的aar包是debug版本,若是須要構建release版本,只須要把命令中的debug換成release便可。 打包構建的flutter-debug.aar位於.android/Flutter/build/outputs/aar/目錄下,能夠把它拷貝到原生Android工程的app/libs目錄下,而後在原生Android工程的app目錄的打包配置build.gradle中添加對它的依賴,以下所示。
dependencies {
implementation(name: 'flutter-debug', ext: 'aar')
}
複製代碼
而後從新編譯一下項目,若是沒有任何錯誤提示則說明Flutter模塊被成功集成到Android原生工程中。
原生iOS工程對Flutter的依賴包含Flutter庫和引擎,以及Flutter工程編譯產物。其中,Flutter 庫和引擎指的是Flutter.framework等,Flutter工程編譯產物指的是 App.framework等。 在原生iOS工程中集成Flutter須要先配置好CocoaPods,CocoaPods是iOS的類庫管理工具,用來管理第三方開源庫。在原生iOS工程中執行pod init命令建立一個Podfile文件,而後在Podfile文件中添加Flutter模塊依賴,以下所示。
flutter_application_path = '../flutter_ library/ load File.join(flutter_application_path, '.ios', 'Flutter', 'podhelper.rb') target 'iOSDemo' do # Comment the next line if you don't want to use dynamic frameworks
use_frameworks!
install_all_flutter_pods(flutter_application_path)
# Pods for iOSDemo
… //省略其餘腳本
end ' 複製代碼
而後,關閉原生iOS工程,並在原生iOS工程的根目錄執行pod install命令安裝所需的依賴包。安裝完成後,使用Xcode打開iOSDemo.xcworkspace原生工程。 默認狀況下,Flutter是不支持Bitcode的,Bitcode是一種iOS編譯程序的中間代碼,在原生iOS工程中集成Flutter須要禁用Bitcode。在Xcode中依次選擇【TAGETS】→【Build Setttings】→【Build Options】→【Enable Bitcode】來禁用Bitcode,以下圖所示。
"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh" build
"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh" embed
複製代碼
不過,最新版本的Flutter已經不須要再添加腳本了。從新運行原生iOS工程,若是沒有任何錯誤則說明iOS成功集成Flutter模塊。 除了使用Flutter模塊方式外,還能夠將Flutter模塊打包成能夠依賴的動態庫,而後再使用CocoaPods添加動態庫。首先,在flutter_library根目錄下執行打包構建命令生成framework動態庫,以下所示。
flutter build ios --debug
複製代碼
上面命令是將Flutter工程編譯成Flutter.framework和App.framework動態庫。若是要生成release版本,只須要把命令中的debug換成release便可。 而後,在原生iOS工程的根目錄下建立一個名爲FlutterEngine的目錄,並把生成的兩個framework動態庫文件拷貝進去。不過,iOS生成模塊化產物要比Android多一個步驟,由於須要把Flutter工程編譯生成的庫手動封裝成一個pod。首先,在flutter_ library該目錄下建立FlutterEngine.podspec,而後添加以下腳本代碼。
Pod::Spec.new do |s|
s.name = 'FlutterEngine'
s.version = '0.1.0'
s.summary = 'FlutterEngine'
s.description = <<-DESC
TODO: Add long description of the pod here.
DESC
s.homepage = 'https://github.com/xx/FlutterEngine'
s.license = { :type => 'MIT', :file => 'LICENSE' }
s.author = { 'xzh' => '1044817967@qq.com' }
s.source = { :git => "", :tag => "#{s.version}" }
s.ios.deployment_target = '9.0'
s.ios.vendored_frameworks = 'App.framework', 'Flutter.framework'
end
複製代碼
而後,執行pod lib lint命令便可拉取Flutter模塊所需的組件。接下來,在原生iOS工程的Podfile文件添加生成的庫便可。
target 'iOSDemo' do
pod 'FlutterEngine', :path => './'
end
複製代碼
從新執行pod install命令安裝依賴庫,原生iOS工程集成Flutter模塊就完成了。接下來,使用Xcode打開ViewController.m文件,而後添加以下代碼。
#import "ViewController.h"
#import <Flutter/Flutter.h>
#import <FlutterPluginRegistrant/GeneratedPluginRegistrant.h>
@interface ViewController ()
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
UIButton *button = [[UIButton alloc]init];
[button setTitle:@"加載Flutter模塊" forState:UIControlStateNormal];
button.backgroundColor=[UIColor redColor];
button.frame = CGRectMake(50, 50, 200, 100);
[button setTitleColor:[UIColor redColor] forState:UIControlStateHighlighted];
[button addTarget:self action:@selector(buttonPrint) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:button];
}
- (void)buttonPrint{
FlutterViewController * flutterVC = [[FlutterViewController alloc]init];
[flutterVC setInitialRoute:@"defaultRoute"];
[self presentViewController:flutterVC animated:true completion:nil];
}
@end
複製代碼
在上面的代碼中,咱們在原生iOS中建立了一個按鈕,點擊按鈕時就會跳轉到Flutter頁面,最終效果以下圖所示。
衆所周知,Flutter的優點之一就是在開發過程當中使用熱重載功能來實現快速調試。默認狀況下,在原生工程中集成Flutter模塊後熱重載功能是失效的,須要從新運行原生工程才能看到效果。如此一來,Flutter開發的熱重載優點就失去了,而且開發效率也隨之下降。 那麼,能不能在混合項目中開啓Flutter的熱重載呢?答案是能夠的,只須要通過以下步驟便可開啓熱重載功能。首先,關閉原生應用,此處所說的關閉是指關閉應用的進程,而不是簡單的退出應用。在Flutter模塊的根目錄中輸入flutter attach命令,而後再次打開原生應用,就會看到鏈接成功的提示,以下圖所示。