官方提供的集成步驟詳見:
https://github.com/flutter/flutter/wiki/Add-Flutter-to-existing-apps
目前混合開發(fā)的集成方案還是preview版本,所以實(shí)際使用過程中,容易碰到各種問題锨匆,還不夠穩(wěn)定尼荆。
本文配置基于:
1.7.8-hotfix-4
官方文檔只能用于master分支,所以會有一些細(xì)節(jié)差異崩掘。
創(chuàng)建Flutter工程
假設(shè)當(dāng)前目錄結(jié)構(gòu)如下翼抠,ios和android工程在同一目錄下:
some/path/
- android_project/
- ios_project/
進(jìn)入some/path/目錄,創(chuàng)建Flutter module:
flutter create -t module --org com.example my_flutter
執(zhí)行完后扼鞋,目錄結(jié)構(gòu)如下:
some/path/
- android_project/
- ios_project/
- my_flutter
my_flutter會生成隱藏的.android和.ios文件夾申鱼,注意盡量不要在這兩個隱藏文件夾里面添加自己的代碼,在pubspec.yaml更新時云头,這兩個文件夾會被重新覆蓋捐友,導(dǎo)致后來添加的文件丟失。
配置Android工程
修改原生工程android_project下的app module中的build.gradle盘寡,在android{}配置中添加一下內(nèi)容
android {
//...
compileOptions {
sourceCompatibility 1.8
targetCompatibility 1.8
}
}
依賴Flutter Module工程的方式有兩種:依賴aar與直接依賴源碼
依賴aar
$ cd some/path/my_flutter
$ flutter build aar
注意:build aar命令到1.7.8-hotfix-4還不支持楚殿,master分支已經(jīng)更新。
在flutter module工程竿痰,使用flutter build命令構(gòu)建出一個aar脆粥,然后android_project就去配置依賴這個aar,這樣做的優(yōu)點(diǎn)是android_project項(xiàng)目編譯的時候不需要去依賴Flutter SDK影涉,
直接引用aar即可变隔,缺點(diǎn)是開發(fā)的時候,沒法一鍵運(yùn)行蟹倾。
依賴源碼
依賴源碼匣缘,可以一鍵運(yùn)行,不過android_project項(xiàng)目編譯的時候需要去依賴Flutter SDK鲜棠。
android_project項(xiàng)目在setting.gradle添加以下代碼
include ':app' // assumed existing content
setBinding(new Binding([gradle: this])) // new
evaluate(new File( // new
settingsDir.parentFile, // new
'my_flutter/.android/include_flutter.groovy' // new
))
目錄結(jié)構(gòu)如下:
Flutter工程以及在pubspec.yaml引用的library肌厨,就能作為一個project被引入,最后在build.gradle添加依賴Flutter工程:
dependencies {
implementation project(':flutter')
}
調(diào)起Flutter界面
Android端
1豁陆、使用FlutterView
// MyApp/app/src/main/java/some/package/MainActivity.java
View flutterView = Flutter.createView(
MainActivity.this,
getLifecycle(),
"route1"
);
FrameLayout.LayoutParams layout = new FrameLayout.LayoutParams(600, 800);
layout.leftMargin = 100;
layout.topMargin = 200;
addContentView(flutterView, layout);
2柑爸、使用FlutterFragment
// MyApp/app/src/main/java/some/package/MainActivity.java
FragmentTransaction tx = getSupportFragmentManager().beginTransaction();
tx.replace(R.id.someContainer, Flutter.createFragment("route1"));
tx.commit();
3、使用FlutterActivity
public class MainActivity extends FlutterActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
GeneratedPluginRegistrant.registerWith(this);
}
}
FlutterActivity可以通過intent指定routeName
intent.putExtra("route", "initRoute");
Flutter端
import 'dart:ui';
import 'package:flutter/material.dart';
void main() => runApp(_widgetForRoute(window.defaultRouteName));
Widget _widgetForRoute(String route) {
switch (route) {
case 'route1':
return SomeWidget(...);
case 'route2':
return SomeOtherWidget(...);
default:
return Center(
child: Text('Unknown route: $route', textDirection: TextDirection.ltr),
);
}
}
創(chuàng)建FlutterView或者FlutterFragment時盒音,傳入了一個initialRoute表鳍,也就是window.defaultRouteName的值,這樣我們就能夠根據(jù)routeName來決定跳轉(zhuǎn)到哪個Flutter頁面祥诽。
配置ios工程
集成Flutter module工程到flutter_host_ios工程需要Cocoapods依賴項(xiàng)管理器譬圣,請確保本地安裝了cocoapods,如果未安裝雄坪,可以參考:cocoapods.org/
1厘熟、如果ios_project工程中已經(jīng)使用了cocoapods,將下列配置添加到工程的Podfile文件中:
flutter_application_path = 'path/to/my_flutter/'
load File.join(flutter_application_path, '.ios', 'Flutter', 'podhelper.rb')
2、找到項(xiàng)目TARGETS的Build Phases绳姨,點(diǎn)擊左上角+號選擇New Run Script Phase添加Run Script颇玷,在Shell字段下添加下面兩行腳本
"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh" build
"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh" embed
這段跟官方文檔有差異,如果是master分支就缆,參考官方文檔。
2谒亦、執(zhí)行pod install
每次pubspec.yaml依賴有更新時竭宰,都需要重新執(zhí)行pod install
3、因?yàn)镕lutter現(xiàn)在不支持bitcode份招,需要禁用項(xiàng)目TARGETS的Build Settings-> Build Options-> Enable Bitcode部分中的ENABLE_BITCODE標(biāo)志切揭。
調(diào)起Flutter界面
在ios_project中,將AppDelegate改為繼承FlutterAppDelegate锁摔。
AppDelegate.h
#import <UIKit/UIKit.h>
#import <Flutter/Flutter.h>AppDelegate.m
@interface AppDelegate : FlutterAppDelegate
@property (nonatomic,strong) FlutterEngine *flutterEngine;
@end
AppDelegate.m
#import <FlutterPluginRegistrant/GeneratedPluginRegistrant.h> // Only if you have Flutter Plugins
#include "AppDelegate.h"
@implementation AppDelegate
// This override can be omitted if you do not have any Flutter Plugins.
- (BOOL)application:(UIApplication *)application
didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
self.flutterEngine = [[FlutterEngine alloc] initWithName:@"io.flutter" project:nil];
[self.flutterEngine runWithEntrypoint:nil];
[GeneratedPluginRegistrant registerWithRegistry:self.flutterEngine];
return [super application:application didFinishLaunchingWithOptions:launchOptions];
}
@end
ViewController.m
#import <Flutter/Flutter.h>
#import "AppDelegate.h"
#import "ViewController.h"
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
[button addTarget:self
action:@selector(handleButtonAction)
forControlEvents:UIControlEventTouchUpInside];
[button setTitle:@"Press me" forState:UIControlStateNormal];
[button setBackgroundColor:[UIColor blueColor]];
button.frame = CGRectMake(80.0, 210.0, 160.0, 40.0);
[self.view addSubview:button];
}
- (void)handleButtonAction {
FlutterEngine *flutterEngine = [(AppDelegate *)[[UIApplication sharedApplication] delegate] flutterEngine];
FlutterViewController *flutterViewController = [[FlutterViewController alloc] initWithEngine:flutterEngine nibName:nil bundle:nil];
[self presentViewController:flutterViewController animated:false completion:nil];
}
@end
與Android一樣廓旬,F(xiàn)lutterViewController也可以設(shè)置routeName
[flutterViewController setInitialRoute:@"route1"];
但是,這個api目前基本是無法派上用場谐腰,上述例子共用了FlutterEngine孕豹,在runWithEntrypoint執(zhí)行之后,main.dart中runApp代碼已經(jīng)執(zhí)行十气,后面再去setInitialRoute已經(jīng)沒有效果励背,F(xiàn)lutterViewController使用initWithNibName等其他方式初始化,不共用FlutterEngine砸西,main.dart還沒執(zhí)行叶眉,這種方式setInitialRoute能夠起作用,不過跳轉(zhuǎn)到Flutter頁面時芹枷,會展示launch頁面衅疙,體驗(yàn)不好。
熱重載
在宿主app進(jìn)程運(yùn)行以后鸳慈,進(jìn)入my_flutter,執(zhí)行:
$ cd some/path/my_flutter
$ flutter attach
Waiting for a connection from Flutter on Nexus 5X...
attach成功之后饱溢,就可以隨時修改flutter代碼,進(jìn)行熱重載更新蝶涩。