APP下载

Flutter与Android完美结合-Google模式

消息来源:baojiabao.com 作者: 发布时间:2024-05-04

报价宝综合消息Flutter与Android完美结合-Google模式

前言

Flutter的工程结构比较特殊,由Flutter目录再分别包含Native工程的目录(即ios和android两个目录)组成。预设情况下,引入了Flutter的Native工程无法脱离父目录进行独立构建和执行,因为它会反向依赖于Flutter相关的库和资源。

在拥有了Native工程的情况下,开发者不太可能去建立一个全新的Flutter工程重写整个产品,因此Flutter工程将包含已有的Native工程,这样就带来了一系列问题:

flutter专案目录结构

1.构建打包问题

引入Flutter后,Native工程因对其有了依赖和耦合,从而无法独立编译构建。在Flutter环境下,工程的构建是从Flutter的构建命令开始,执行过程中包含了Native工程的构建,开发者要配置完整的Flutter执行环境才能走通整个流程;

2.混合变异带来的开发效率的降低

在转型Flutter的过程中必然有许多业务仍使用Native进行开发,工程结构的改动会使开发无法在纯Native环境下进行,而适配到Flutter工程结构对纯Native开发来说又会造成不必要的构建步骤,造成开发效率的降低。

Flutter嵌入Android已有专案解决方案

对于开发者对于Flutter的混合模式开发呼声,Google专门为了这个问题建立了Wiki并且进行了持续4个月42个版本的更新。

最终确定以module的形式引入Flutter工程达到内嵌的目的。这种方式分为两种,第一种是在native工程当前目录下建立Flutter的module模式,第二种是在native工程的同级目录下建立Flutter的module模式。下面介绍第一种方案。

1.工程目录结构

为了让Android工程和Flutter工程互不干扰,这里不再以Android工程为工程的根目录,而是让Android工程和平级的Flutter工程的公共目录作为根目录。 最终的目录结构应该是下面这样的

你的专案根目录(随便什么你喜欢的地方)

├── 原生安卓工程(FlutterInAndroid)

└── Flutter工程(my_flutter)

所以首先在你的专案根目录下用AS建立一个新的Android原生专案,可以勾选上kotlin支援,这样更舒服。 建立完成后你会得到一个这样的结构

你的专案根目录(随便什么你喜欢的地方)

└── FlutterInAndroid

FlutterInAndroid目录内是一个完整的Android工程

2.module模式建立Flutter工程

接下来使用Flutter命令来建立module工程,在你的专案根目录下执行:

flutter create -t module my_flutter

建立完成后你会得到一个这样的结构

你的专案根目录(随便什么你喜欢的地方)

├── FlutterInAndroid

└── my_flutter

my_flutter是一个Flutter的module工程,用来供Android专案引入。

这个时候会看到project中新增加了一个flutter_module,其中包含了.android,.ios和关键的include_flutter.groovy档案

3.在Android工程中引入依赖

在FlutterInAndroid这个Android工程的setting.gradle档案中追加flutter工程的引入

你的专案跟目录/FlutterInAndroid/setting.gradle

include ':app'

//加入下面配置

setBinding(new Binding([gradle: this]))

evaluate(new File(

settingsDir.parentFile,

'my_flutter/.android/include_flutter.groovy'

))

在app的build.gradle档案中加入工程依赖

你的专案跟目录/FlutterInAndroid/app/build.gradle

...

dependencies {

...

// 加入下面配置

implementation project(':flutter')

}

使用AS开启FlutterInAndroid工程,重新构建专案,即可成功的将Flutter加入Android工程。

4.在Android工程中建立Flutter的View

Flutter提供了两种方式让Android工程来引用元件,一种是View,一种是Fragment,这里选用View来进行讲解,Fragment同理。 这里我们用两种方式来引入FLutter,本质是还是是作为一个view引入布局还是将FlutterView作为Activity的根View。

(1)以单个view引入布局

val flutterView = Flutter.createView(this,lifecycle,"route1")

通过上面很简单的一个方法,我们就能通过Flutter创建出一个view,这个方法提供三个引数,第一个是Activity,第二个引数是一个Lifecycle物件,我们之间取Activity的lifecycle即可,第三个引数是告诉Flutter我们要建立一个什么样的view,这个字串引数可以在Flutter工程中获取得到。

创建出这个FlutterView之后就可以按常规的操作来将它加入到任何你想要的布局中去了。

(2)以根view作为Activity

建立一个空的Activity,用Flutter建立一个View作为页面的根View:

class FlutterActivity : AppCompatActivity() {

override fun onCreate(savedInstanceState: Bundle?) {

super.onCreate(savedInstanceState)

setContentView(R.layout.activity_flutter)

val flutterView = Flutter.createView(this[email protected],lifecycle,"route1")

val layout = FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams.MATCH_PARENT)

addContentView(flutterView, layout)

}

}

这里我们并没有使用setContentView而是是用了addContentView这个方法,原因是这样的:

虽然FLutter的载入速度非常快,但是这个过程依然存在,在建立FLutterView之前我们先给ContentView设定了一个R.layout.activity_flutter布局,这个布局可以作为FlutterView载入完成之前展示给使用者的界面,当然大部分情况下使用者根本感知不到这个界面Flutter已经载入完成了,但我们仍需要它,因为debug模式下造成Flutter的载入速度并不是非常快,这个界面可以给开发人员看,还有就是如果没有这个界面的话在Activity的载入过程会出现一个黑色的闪屏,而这个情况对使用者来说并不友好。

5.在Flutter工程中根据不同的route建立不同的元件

用AndroidStudio在你的专案跟目录/my_flutter开启Flutter工程,这时候AndroidStudio外挂会识别到Flutter工程并以Flutter工程进行载入。

忽略掉.android和.ios资料夹之后你会发现,这个FLutter工程和完整的Flutter工程并没有任何不同,你依然能够以完整Flutter工程的流程来进行Flutter开发并启动除错,这是一个非常人性化的设计。

上面我们在原生Android工程中以View的形式呼叫了Flutter,而Flutter本质上是只有一个入口的,也就是main.dart档案中的main函式:

void main() => runApp(new MyApp());

我们的目的是根据原生工程的呼叫让Flutter生成不同的元件作为View来供原生工程使用,那么我们就可以从这个main函式来入手。

通过文件我们可以通过window的全域性变数中获取到当前的routeName,这个值正是上面通过原生工程传给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),

);

}

}

6.让Flutter模组支援热载入

首先在Flutter目录下启动监听服务,在你的专案根目录/my_flutter下执行

flutter attach

执行后,监听服务会等待并监听debug应用中flutter的状态

然后在开启FlutterInAndroid专案的AS中以正常方式除错执行,在真机或模拟器中执行app后并不会立即出发flutter的监听服务,当flutter的view或Fragment启用时才会触发。

当flutter的监听服务和app建立连线后,终端会出现如下输出:

$ flutter attach -d W8

Waiting for a connection from Flutter on PLK UL00...

Done.

Syncing files to device PLK UL00... 8.7s

To hot reload changes while running, press "r". To hot restart (and rebuild state), press "R".

An Observatory debugger and profiler on PLK UL00 is available at: http://127.0.0.1:54218/

For a more detailed help message, press "h". To quit, press "q".

这时我们修改flutter工程中的dart程式码档案,储存后在终端中点选r键即可进行热载入,R键进行热重启。

7.签名打包

引入flutter工程后,对Android原生工程的构建基本上没有影响,打包按常规操作即可。

2019-11-11 15:56:00

相关文章