0%

Flutter 基本使用

一、 Flutter 混合开发

Flutter 环境配置

1. Flutter 整体架构

flutter

2. Flutter 开发环境配置

Flutter环境

1
2
3
$ cd ~/development
$ unzip ~/Downloads/flutter_macos_v1.9.1+hotfix.4-stable.zip
$ export PATH="$PATH:`pwd`/flutter/bin"

Android SDK

1
$ export ANDROID_HOME=/Users/*/Library/Android/sdk

Xcode 安装

1
$ sudo xcode-select --switch /Applications/Xcode.app/Contents/Developer

3. Flutter 常用命令

1
2
3
4
5
6
## flutter 环境诊断
$ flutter doctor
## flutter 版本切换
$ flutter version v1.5.4-hotfix.2
## flutter 创建工程模板
$ flutter create --org com.exemple --template=[plugin,app,package,module] projectname

4. Flutter接入及原理

Flutter开发方式,目前有4种,分别是:纯的Dart库开发、Flutter应用开发、Flutter插件开发以及Flutter Module接入。下面,分别对这4种开发形式做一个介绍。

4.1 纯的Dart库开发

纯的Dart库开发,无客户端相关Native代码,通过命令行生成工程模板:

1
$ flutter create --org com.exemple --template=package somepackage
image-20191024191219392
4.2 Flutter应用开发

Flutter应用开发,可直接运行,适合开发新的APP。

1
$ flutter create --org com.exemple --template=app someapp

从目录结构可以看出,此工程中有3个目录:android、ios、lib,android目录下是与Android平台相关的代码及配置,ios目录下是与iOS平台相关的代码及配置,lib目录下为flutter平台相关的代码。

pubspec.yaml为flutter工程相关的配置,包含依赖的插件、资源等。.flutter-plugins 文件为flutter插件路径映射文件。

我们以Android开发者的角度,简单看一下,Flutter是如何被引入到Android项目中的。

在Android工程中 settings.gralde 文件中,我们可以看到,主要做了以下几件事情:

1
2
3
4
5
6
7
8
9
10
11
12
include ':app' 
def flutterProjectRoot = rootProject.projectDir.parentFile.toPath()
def plugins = new Properties()
def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins')
if (pluginsFile.exists()) {
pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) }
}
plugins.each { name, path ->
def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile()
include ":$name"
project(":$name").projectDir = pluginDirectory
}
  1. 寻找.flutter-plugins 文件并读取配置
  2. .flutter-plugins配置中的库引入工程中

.flutter-plugins 中的内容:

1
2
flutter_boost=/Users/zauther/.pub-cache/hosted/pub.flutter-io.cn/flutter_boost-0.1.54/
xservice_kit=/Users/zauther/.pub-cache/hosted/pub.flutter-io.cn/xservice_kit-0.0.29/

在app对应的 build.gradle 文件中,前面的配置代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
def localProperties = new Properties()
def localPropertiesFile = rootProject.file('local.properties')
if (localPropertiesFile.exists()) {
localPropertiesFile.withReader('UTF-8') { reader ->
localProperties.load(reader)
}
}

def flutterRoot = localProperties.getProperty('flutter.sdk')
if (flutterRoot == null) {
throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.")
}

def flutterVersionCode = localProperties.getProperty('flutter.versionCode')
if (flutterVersionCode == null) {
flutterVersionCode = '1'
}

def flutterVersionName = localProperties.getProperty('flutter.versionName')
if (flutterVersionName == null) {
flutterVersionName = '1.0'
}

apply plugin: 'com.android.application'
apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle"
......
flutter {
source '../..'
}
......

可以看出主要做了一下几件事:

  1. 读取 local.properties 配置
  2. 从配置中读取flutter.sdk、flutter.versionCode、flutter.versionName
  3. 通过flutter.sdk路径找到 flutter.gradle ,此文件即为flutter编译流程文件,后面单独介绍
  4. 设置flutter对应的lib所在目录,lib中包含flutter代码入口 main.dart
4.3 Flutter 插件开发

Flutter插件类似于Java开发过程中的库,可在目前项目上直接引入已有功能。

1
$ flutter create --org com.exemple --template=plugin someplugin
image-20191019005837181

目录结构同Flutter应用,其中example模块为一个独立的flutter 工程,可用于测试插件。通过这个例子,以Android开发者视角,来看一下插件是插件如何编写以及被引入的。

Flutter与Native的通讯分为2种:一是Flutter主动调用Native,并获取Native的返回结果;二是Native主动调用Flutter,并获取Flutter返回结果。

Flutter调用Native

在flutter插件的android目录下,新建类Testflutterplugin2Plugin,实现MethodCallHandler接口:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
/** Testflutterplugin2Plugin */
public class Testflutterplugin2Plugin implements MethodCallHandler {
/** Plugin registration. */
public static void registerWith(Registrar registrar) {
final MethodChannel channel = new MethodChannel(registrar.messenger(), "testflutterplugin2");
channel.setMethodCallHandler(new Testflutterplugin2Plugin());
}
@Override
public void onMethodCall(MethodCall call, Result result) {
if (call.method.equals("getPlatformVersion")) {
result.success("Android " + android.os.Build.VERSION.RELEASE);
} else if(call.method.equals("FUNC")){
try {
// do something
result.success("do something");
}catch (Exception e){
// catch error
result.error("ERROR","do something error",null);
}
}else {
result.notImplemented();
}
}
}

方法registerWith中,通过Registrar创建MethodChannel,并将Testflutterplugin2Plugin加入到MethodChannel中。

在onMethodCall方法中,参数MethodCall包含有Flutter调用的方法名以及传入参数,Result对象用于返回Native的处理结果给Flutter。

在Flutter代码中:

1
2
3
4
5
6
7
8
9
class Testflutterplugin2 {
static const MethodChannel _channel =
const MethodChannel('testflutterplugin2');

static Future<String> get platformVersion async {
final String version = await _channel.invokeMethod('getPlatformVersion');
return version;
}
}
Native调用Flutter
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public class Testflutterplugin2EventChannel implements EventChannel.StreamHandler {
public static void registerWith(PluginRegistry.Registrar registrar) {
final EventChannel channel = new EventChannel(registrar.messenger(), "testflutterplugin2.eventchannel");
channel.setStreamHandler(new Testflutterplugin2EventChannel());
}
@Override
public void onListen(Object arguments, EventChannel.EventSink eventSink) {
try {
eventSink.success("success");
} catch (Exception e) {
eventSink.error("error", "Testflutterplugin2EventChannel error", null);
}
}
@Override
public void onCancel(Object arguments) {

}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
class Testflutterplugin2EventChannel {
static const EventChannel _eventChannel =
const EventChannel('testflutterplugin2.eventchannel');

static void test() {
_eventChannel.receiveBroadcastStream('arguments').listen((result) {},
onError: (e) {}, onDone: () {}, cancelOnError: true);
}

static void test1() {
_eventChannel.receiveBroadcastStream().listen((result) {},
onError: (e) {}, onDone: () {}, cancelOnError: true);
}
}
Android平台下的插件引入

Android目录中的代码为Android与Flutter桥接的部分:

settings.gradlerootProject.name = 'testflutterplugin2' 只是声明了Android模块,build.gralde 中为Android相关的配置项。

插件代码

插件实现了MethodCallHandler 接口,实现了onMethodCall 方法。

registerWith 方法中:通过传入的Registrar对象,新建MethodChannel,并指定其名testflutterplugin2

设置MethodChannel的处理方法Testflutterplugin2Plugin。这段代码主要作用用于注册处理方法Testflutterplugin2Plugin到Registrar。而MethodChannel只是对这个注册过程的一个封装。

查看MethodChannel核心代码:

1
2
3
public void setMethodCallHandler(@Nullable MethodChannel.MethodCallHandler handler) {
this.messenger.setMessageHandler(this.name, handler == null ? null : new MethodChannel.IncomingMethodCallHandler(handler));
}

在实现MethodCallHandler接口的类中,对于onMethodCall方法:

MethodCall对象中包含了来自于Flutter的调用方法名和参数信息。其中,arguments为Map对象或JSONObject

1
2
public final String method;
public final Object arguments;

Result接口中包含Native端的返回给Flutter测的结果信息。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
public void onMessage(ByteBuffer message, final BinaryReply reply) {
MethodCall call = MethodChannel.this.codec.decodeMethodCall(message);

try {
this.handler.onMethodCall(call, new MethodChannel.Result() {
public void success(Object result) {
reply.reply(MethodChannel.this.codec.encodeSuccessEnvelope(result));
}

public void error(String errorCode, String errorMessage, Object errorDetails) {
reply.reply(MethodChannel.this.codec.encodeErrorEnvelope(errorCode, errorMessage, errorDetails));
}

public void notImplemented() {
reply.reply((ByteBuffer)null);
}
});
} catch (RuntimeException var5) {
Log.e("MethodChannel#" + MethodChannel.this.name, "Failed to handle method call", var5);
reply.reply(MethodChannel.this.codec.encodeErrorEnvelope("error", var5.getMessage(), (Object)null));
}
}

在IncomingResultHandler中,Result的匿名内部类中,通过BinaryReply将Native端的处理结果经StandardMethodCodec类,编码后传递给Flutter侧。

插件的引入

在example模块中,在MainActivity.javaonCreate 中:

1
2
3
4
5
6
7
public class MainActivity extends FlutterActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
GeneratedPluginRegistrant.registerWith(this);
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
/**
* Generated file. Do not edit.
*/
public final class GeneratedPluginRegistrant {
public static void registerWith(PluginRegistry registry) {
if (alreadyRegisteredWith(registry)) {
return;
}
Testflutterplugin2Plugin.registerWith(registry.registrarFor("cn.cwiki.flutter.test.testflutterplugin2.Testflutterplugin2Plugin"));
}

private static boolean alreadyRegisteredWith(PluginRegistry registry) {
final String key = GeneratedPluginRegistrant.class.getCanonicalName();
if (registry.hasPlugin(key)) {
return true;
}
registry.registrarFor(key);
return false;
}
}
1
2
3
4
<application
android:name="io.flutter.app.FlutterApplication"
android:label="testflutterplugin2_example"
android:icon="@mipmap/ic_launcher">
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public class FlutterApplication extends Application {
private Activity mCurrentActivity = null;

public FlutterApplication() {
}

@CallSuper
public void onCreate() {
super.onCreate();
FlutterMain.startInitialization(this);
}

public Activity getCurrentActivity() {
return this.mCurrentActivity;
}

public void setCurrentActivity(Activity mCurrentActivity) {
this.mCurrentActivity = mCurrentActivity;
}
}

FlutterApplication中核心作用是 FlutterMain.startInitialization(this); 初始化Flutter框架

新建Flutter Module

1
$ flutter create --org com.exemple --template=plugin somemodule
image-20191020105011609

settings.gradle

1
2
3
4
5
include ':app'

rootProject.name = 'android_generated'
setBinding(new Binding([gradle: this]))
evaluate(new File('include_flutter.groovy'))

include_flutter.groovy

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
def scriptFile = getClass().protectionDomain.codeSource.location.toURI()
def flutterProjectRoot = new File(scriptFile).parentFile.parentFile
gradle.include ':flutter'
gradle.project(':flutter').projectDir = new File(flutterProjectRoot, '.android/Flutter')
def plugins = new Properties()
def pluginsFile = new File(flutterProjectRoot, '.flutter-plugins')
if (pluginsFile.exists()) {
pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) }
}
plugins.each { name, path ->
def pluginDirectory = flutterProjectRoot.toPath().resolve(path).resolve('android').toFile()
gradle.include ":$name"
gradle.project(":$name").projectDir = pluginDirectory
}
gradle.getGradle().projectsLoaded { g ->
g.rootProject.beforeEvaluate { p ->
_mainModuleName = binding.variables['mainModuleName']
if (_mainModuleName != null && !_mainModuleName.empty) {
p.ext.mainModuleName = _mainModuleName
}
}
g.rootProject.afterEvaluate { p ->
p.subprojects { sp ->
if (sp.name != 'flutter') {
sp.evaluationDependsOn(':flutter')
}
}
}
}

Android Flutter 编译任务

Android 端Flutter编译过程
  1. 设置变异类型

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    project.android.buildTypes {
    profile {
    // ...
    }
    dynamicProfile {
    // ...
    }
    dynamicRelease {
    // ...
    }
    }
  2. 设置Flutter Engine,如果本地有配置,则会使用本地的

    1
    2
    3
    4
    5
    if (project.hasProperty('localEngineOut')) {
    // 设置配置的Engine
    } else {
    // 设置Flutter SDK中的Engine
    }
  3. 添加FlutterTask,并设置Flutter插件的依赖

    1
    2
    3
    4
    5
    6
    project.extensions.create("flutter", FlutterExtension)
    project.afterEvaluate this.&addFlutterTask
    //...
    plugins.each { name, _ ->
    // ...
    }
FlutterTask
  1. 设置编译参数

    flutter 代码路径:

    1
    2
    3
    4
    5
    6
    7
    String target = project.flutter.target
    if (target == null) {
    target = 'lib/main.dart'
    }
    if (project.hasProperty('target')) {
    target = project.property('target')
    }

    编译目标平台:

    1
    2
    3
    4
    String targetPlatformValue = null
    if (project.hasProperty('target-platform')) {
    targetPlatformValue = project.property('target-platform')
    }

    等等。

  2. 添加Flutter依赖以及FlutterTask

    1
    2
    3
    4
    5
    if (project.android.hasProperty("applicationVariants")) {
    project.android.applicationVariants.all addFlutterDeps
    } else {
    project.android.libraryVariants.all addFlutterDeps
    }

    包含:vm_snapshot_data、vm_snapshot_instr、isolate_snapshot_data、isolate_snapshot_instr等,以及Flutter源代码等。Flutter 的编译过程是由源代码编译的,插件等提供的也是源代码依赖。

  3. FlutterTask

    Flutter 执行的便于指令:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    void buildBundle() {
    if (!sourceDir.isDirectory()) {
    throw new GradleException("Invalid Flutter source directory: ${sourceDir}")
    }

    intermediateDir.mkdirs()

    if (buildMode == "profile" || buildMode == "release") {
    project.exec {
    executable flutterExecutable.absolutePath
    workingDir sourceDir
    if (localEngine != null) {
    args "--local-engine", localEngine
    args "--local-engine-src-path", localEngineSrcPath
    }
    args "build", "aot"
    args "--suppress-analytics"
    args "--quiet"
    args "--target", targetPath
    args "--target-platform", "android-arm"
    args "--output-dir", "${intermediateDir}"
    if (trackWidgetCreation) {
    args "--track-widget-creation"
    }
    if (extraFrontEndOptions != null) {
    args "--extra-front-end-options", "${extraFrontEndOptions}"
    }
    if (extraGenSnapshotOptions != null) {
    args "--extra-gen-snapshot-options", "${extraGenSnapshotOptions}"
    }
    if (buildSharedLibrary) {
    args "--build-shared-library"
    }
    if (targetPlatform != null) {
    args "--target-platform", "${targetPlatform}"
    }
    args "--${buildMode}"
    }
    }

    project.exec {
    executable flutterExecutable.absolutePath
    workingDir sourceDir
    if (localEngine != null) {
    args "--local-engine", localEngine
    args "--local-engine-src-path", localEngineSrcPath
    }
    args "build", "bundle"
    args "--suppress-analytics"
    args "--target", targetPath
    if (verbose) {
    args "--verbose"
    }
    if (fileSystemRoots != null) {
    for (root in fileSystemRoots) {
    args "--filesystem-root", root
    }
    }
    if (fileSystemScheme != null) {
    args "--filesystem-scheme", fileSystemScheme
    }
    if (trackWidgetCreation) {
    args "--track-widget-creation"
    }
    if (compilationTraceFilePath != null) {
    args "--compilation-trace-file", compilationTraceFilePath
    }
    if (createPatch) {
    args "--patch"
    args "--build-number", project.android.defaultConfig.versionCode
    if (buildNumber != null) {
    assert buildNumber == project.android.defaultConfig.versionCode
    }
    }
    if (baselineDir != null) {
    args "--baseline-dir", baselineDir
    }
    if (extraFrontEndOptions != null) {
    args "--extra-front-end-options", "${extraFrontEndOptions}"
    }
    if (extraGenSnapshotOptions != null) {
    args "--extra-gen-snapshot-options", "${extraGenSnapshotOptions}"
    }
    if (targetPlatform != null) {
    args "--target-platform", "${targetPlatform}"
    }
    if (buildMode == "release" || buildMode == "profile") {
    args "--precompiled"
    } else {
    args "--depfile", "${intermediateDir}/snapshot_blob.bin.d"
    }
    args "--asset-dir", "${intermediateDir}/flutter_assets"
    if (buildMode == "debug") {
    args "--debug"
    }
    if (buildMode == "profile" || buildMode == "dynamicProfile") {
    args "--profile"
    }
    if (buildMode == "release" || buildMode == "dynamicRelease") {
    args "--release"
    }
    if (buildMode == "dynamicProfile" || buildMode == "dynamicRelease") {
    args "--dynamic"
    }
    }
    }

    flutterExecutable为flutter命令

    当 buildType 为 debug 时:

    1
    $ flutter build bundle --depfile ${intermediateDir}/snapshot_blob.bin.d --debug

    当 buildType 为 release 时:

    1
    2
    $ flutter build aot
    $ flutter build bundle --precompiled --release
Flutter 编译模型区别

https://juejin.im/post/5d68fb1af265da03d063b69e

二、 调试工具Dart DevTools

  1. 启动devtools
1
2
$ pub global run devtools
Serving DevTools at http://127.0.0.1:9100
  1.  在flutter lib同目录执行attach命令,等待App连接
1
2
$ flutter attach
Waiting for a connection from Flutter on MI 8...
  1. 重新启动app,等待
1
2
3
4
5
6
7
8
9
$ flutter attach
Waiting for a connection from Flutter on MI 8...
Done.
Syncing files to device MI 8...
3,832ms (!)

🔥 To hot reload changes while running, press "r". To hot restart (and rebuild state), press "R".
An Observatory debugger and profiler on MI 8 is available at: http://127.0.0.1:53469/Fv75Oo4wMEE=/
For a more detailed help message, press "h". To detach, press "d"; to quit, press "q"
  1. 打开chrome,http://127.0.0.1:9100 ,输入flutter attach 命令中的url http://127.0.0.1:53469/Fv75Oo4wMEE=/
image-20191024193054066
  1. 通过Dart DevTools调试

image-20191024193127816

工具项:

  • Flutter Inspector: 布局调试工具
  • Timeline :
  • Memory : 内存使用情况
  • Performance :
  • Debugger: 断点调试工具
  • Logging : Log输出
  • Hot Reload
  • Hot Restart
Flutter Inspector:Flutter 布局调试工具

Performance Overlay :

image-20191024200900434

Paint Baselines:

image-20191024201205498

Debug Paint:

image-20191024193810095

当项目为Flutter工程时,可以直接通过Android Studio进行调试,当以Module的形式引入时,目前无法直接通过Android Studio进行调试,可采用Dart DevTools在Chrome中调试。

![image-20191024201010180](/Users/zauther/Library/Application Support/typora-user-images/image-20191024201010180.png)

三、Flutter 接入实践

接入现有ReactNative工程

1. 在Android测

  1. 引入Flutter Module
1
2
setBinding(new Binding([gradle: this]))
evaluate(new File(rootProject.projectDir, './fluttermodule/android/include_flutter.groovy'))
  1. 在include_flutter.groovy指定自己的Flutter模块,因为.android目录是自己生成的,内容会被覆盖,可自定义模块
1
2
gradle.include ':flutter'
gradle.project(':flutter').projectDir = new File(flutterProjectRoot, 'android/Flutter')
  1. 定义FlutterActivity,并在AndroidManifest.xml中注册,此处集成FlutterBoost的BoostFlutterActivity,也可以使用Flutter原生的FlutterActivity。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public class FlutterPageActivity extends BoostFlutterActivity {
private String url;
private HashMap params;
@Override
public void onCreate(Bundle saveInstanceBundle) {
// onCreate
}
@Override
public void onRegisterPlugins(PluginRegistry registry) {
// register flutter plugins
}
@Override
public String getContainerName() {
return url == null ? "" : url;
}
@Override
public Map getContainerParams() {
// params of the page
return params == null ? new HashMap() : params;
}
}
1
2
3
4
5
6
7
public class MainActivity extends FlutterActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
GeneratedPluginRegistrant.registerWith(this);
}
}

FlutterActivity,用于承接Flutter界面

  1. 在Application中初始化Flutter框架
1
FlutterMain.startInitialization(context);

如果使用FlutterBoost,在初始化Flutter框架后,初始化FlutterBoost插件:

1
FlutterBoostPlugin.init(platform);

2. 在ReactNative测

  1. 自定义方法
1
2
3
FlutterSupport.openFlutterPage = function (url, params){
NativeModules.RNFlutterSupport.openFlutterPage(url, params)
}
  1. 新建ReactNativeModules,并注册到ReactNativeHost中
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
public class RNFlutterSupportModule extends ReactContextBaseJavaModule{
@ReactMethod
public void openFlutterPage(String url, ReadableMap params) {
// RN侧调用,RNToFlutterManager根据url来判断跳转到哪个Flutter页面
RNToFlutterManager.openFlutterPage(reactContext, url, params == null ? new HashMap() : params.toHashMap(), 0);
}
// RN侧调用Flutter方法
@ReactMethod
public void invokeCallback(String callbackId, ReadableMap data) {
ReactFlutterEventEmitterCallbackEvent callbackEvent = new ReactFlutterEventEmitterCallbackEvent();
callbackEvent.callBackId = callbackId;
callbackEvent.data = data;
mEmitter.onReactCallbackEvent(callbackEvent);
}
// 用于Flutter侧调用RN的方法
public void methodCallReactNative(String method, Object arguments, final Callback callback) {
mEmitter.sendEvent(reactContext, method, arguments, callback == null ? null : new ReactFlutterEventEmitterCallbackHandler() {
@Override
public void handler(ReadableMap data) {
callback.invoke(data.toHashMap());
}
});
}
@Override
public String getName() {
return "RNFlutterSupport";
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public class RNFlutterSupportPackage implements ReactPackage {
public RNFlutterSupportModule mRNFlutterSupportModule;
@Override
public List<NativeModule> createNativeModules(ReactApplicationContext reactContext) {
mRNFlutterSupportModule = new RNFlutterSupportModule(reactContext);
return Arrays.<NativeModule>asList(mRNFlutterSupportModule);
}
// Deprecated from RN 0.47
public List<Class<? extends JavaScriptModule>> createJSModules() {
return Collections.emptyList();
}
@Override
public List<ViewManager> createViewManagers(ReactApplicationContext reactContext) {
return Collections.emptyList();
}
}

其中:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public static void openFlutterPage(Context context, String url, final HashMap params, int requestCode) {
Intent intent = new Intent(context, FlutterPageActivity.class);
intent.putExtra("url", url);
intent.putExtra("params", params);
if (params != null && params.containsKey("flags")) {
String flags = (String) params.get("flags");
if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP && "CLEAR_TASK".equals(flags)) {
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
} else {
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
}
} else {
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
}
context.startActivity(intent);
}

FlutterBoost 使用

在pubspec.yaml添加插件:

1
flutter_boost: ^0.0.415

在Application中:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
FlutterBoostPlugin.init(new IFlutterPlatform() {
@Override
public Application getApplication() {
return null;
}

@Override
public Activity getMainActivity() {
return null;
}

@Override
public boolean isDebug() {
return false;
}

@Override
public boolean startActivity(Context context, String url, int requestCode) {
// flutter 跳转原生
return false;
}

@Override
public Map getSettings() {
return null;
}
});

在Flutter main.dart中注册页面并初始化FlutterBoost:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
class _MyAPPState extends State<MyApp> {
@override
void initState() {
FlutterBoost.singleton.registerPageBuilders({
'teemo.home': (pageName, params, _) => HomePageWidget(params),
'teemo.settings': (pageName, params, _) => SettingPageWidget(params),
'teemo.changeenv': (pageName, params, _) => ChangeEnvPageWidget(params),
'teemo.cabinet.errorreport': (pageName, params, _) =>
ErrorReportPage(params),
'teemo.order.orderdetail': (pageName, params, _) =>
OrderDetailPage(params),
});
FlutterBoost.handleOnStartPage();
super.initState();
}

@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Teemo',
builder: FlutterBoost.init(),
home: new Container(),
localizationsDelegates: [
RefreshLocalizations.delegate,
GlobalMaterialLocalizations.delegate,
GlobalWidgetsLocalizations.delegate,
const FallbackCupertinoLocalisationsDelegate(),
],
supportedLocales: [
const Locale('zh', 'CH'),
const Locale('en', 'US'),
],
);
}
}

Flutter 中跳转页面:

1
2
3
FlutterBoost.singleton.openPage('teemo.settings',
{'canChangeRole': canChangeRole ? "1" : "0"},
animated: true);

FlutterBoost flutter测常用方法:

1
2
3
4
5
6
FlutterBoost.singleton.openPage(String url, Map params,
{bool animated, PageResultHandler resultHandler});
FlutterBoost.singleton.closePage(String url, String pageId, Map params,
{bool animated});
FlutterBoost.singleton.closeCurPage(Map params);
FlutterBoost.handleOnStartPage();