使用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命令,而后再次打开原生应用,就会看到链接成功的提示,以下图所示。