Android项目中集成Flutter,实现秒开Flutter模块

本文目标


成功在Android原生项目中集成Flutter


Warning



  • 从Flutter v1.1.7版本开始,Flutter module仅支持AndroidX应用
  • 在release模式下Flutter仅支持以下架构:x86_64,armeabi-v7a,arm64-v8a,不支持mips和x86,所以引入Flutter前需要选取Flutter支持的架构

android{
//...
defaultConfig {
//配置支持的动态库类型
ndk {
abiFilters 'x86_64','armeabi-v7a', 'arm64-v8a'
}
}
}

混合开发的一些适用场景



  • 在原有项目中加入Flutter页面

image



  • 原生页面中嵌入Flutter模块

image



  • 在Flutter项目中嵌入原生模块

image


主要步骤



  • 创建Flutter module
  • 为已存在的Android项目添加Flutter module依赖
  • 早Kotlin/Java中调用Flutter module
  • 编写Dart代码
  • 运行项目
  • 热重启/重新加载
  • 调试Dart代码
  • 发布应用

请把所有的项目都放在同一个文件夹内


- WorkProject
- AndroidProject
- iOSProject
- flutrter_module

WorkProject下面分别是原生Android模块,原生iOS模块,flutter模块,并且这三个模块是并列结构


创建Flutter module


在做混合开发之前我们需要创建一个Flutter module
这个时候需要


  cd xxx/WorkProject /

创建flutter_module


flutter create -t module flutter_module

如果要指定包名


flutter create -t module --org com.example flutter_module

然后就会创建成功


image



  • .android - flutter_module的Android宿主工程
  • .ios - flutter_module的iOS宿主工程
  • lib - flutter_module的Dart部分代码
  • pubspec.yaml - flutter_module的项目依赖配置文件
    因为宿主工程的存在,我们这个flutter_module在布甲额外的配置的情况下是可以独立运行的,通过安装了Flutter和Dart插件的AndroidStudio打开这个flutter_module项目,通过运行按钮可以直接运行

构建flutter aar(非必须)


可以通过如下命令构建aar


cd .android/
./gradlew flutter:assembleRelease

这会在.android/Flutter/build/outputs/aar/中生成一个flutter-release.aar归档文件


为已存在的Android用意添加Flutter module依赖


打开我们的Android项目的 settings.gradle添加如下代码


setBinding(new Binding([gradle: this]))                              
evaluate(new File(
settingsDir.parentFile,
'flutter_module/.android/include_flutter.groovy'
))

//可选,主要作用是可以在当前AS的Project下显示flutter_module以方便查看和编写Dart代码
include ':flutter_module'
project(':flutter_module').projectDir = new File('../flutter_module')

setBinding与evaluate允许Flutter模块包括它自己在内的任何Flutter插件,在setting.gradle中以类似:flutter package_info :video_player的方式存在


添加:flutter依赖


dependencies {
implementation project(':flutter')
}

添加Java8编译选项


因为Flutter的Android engine使用了Java8的特性,所有在引入Flutter时需要配置你的项目的Java8编译选项


//在app的build.gradle文件的android{}节点下添加
android {
compileOptions {
sourceCompatibility = 1.8
targetCompatibility = 1.8
}
}

在Kotlin中调用Flutter module


支持,我们已经为我们的Android项目添加了Flutter所必须的依赖,接下来我们来看如何在项目中以Kotlin的方式在Fragment中调用Flutter模块,在这里我们能做到让Flutter优化提升加载速度,实现秒开Flutter模块


原生Kotlin端代码


/**
* flutter抽象的基类fragment,具体的业务类fragment可以继承
**/
abstract class FlutterFragment(moduleName: String) : IBaseFragment() {

private val flutterEngine: FlutterEngine?
private lateinit var flutterView: FlutterView

init {
flutterEngine =FlutterCacheManager.instance!!.getCachedFlutterEngine(AppGlobals.get(), moduleName)
}

override fun getLayoutId(): Int {
return R.layout.fragment_flutter
}

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
(mLayoutView as ViewGroup).addView(createFlutterView(activity!!))
}

private fun createFlutterView(context: Context): FlutterView {
val flutterTextureView = FlutterTextureView(activity!!)
flutterView = FlutterView(context, flutterTextureView)
return flutterView
}

/**
* 设置标题
*/
fun setTitle(titleStr: String) {
rl_title.visibility = View.VISIBLE
title_line.visibility = View.VISIBLE
title.text = titleStr
title.setOnClickListener {

}
}

/**
* 生命周期告知flutter
*/
override fun onStart() {
flutterView.attachToFlutterEngine(flutterEngine!!)
super.onStart()
}

override fun onResume() {
super.onResume()
//for flutter >= v1.17
flutterEngine!!.lifecycleChannel.appIsResumed()
}

override fun onPause() {
super.onPause()
flutterEngine!!.lifecycleChannel.appIsInactive()
}

override fun onStop() {
super.onStop()
flutterEngine!!.lifecycleChannel.appIsPaused()
}

override fun onDetach() {
super.onDetach()
flutterEngine!!.lifecycleChannel.appIsDetached()
}

override fun onDestroy() {
super.onDestroy()
flutterView.detachFromFlutterEngine()
}
}

R.layout.fragment_flutter的布局


<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">

<RelativeLayout
android:id="@+id/rl_title"
android:visibility="gone"
android:layout_width="match_parent"
android:layout_height="@dimen/dp_45"
android:background="@color/color_white"
android:gravity="center_vertical"
android:orientation="horizontal">

<TextView
android:id="@+id/title"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_centerInParent="true"
android:layout_gravity="center"
android:gravity="center"
android:textColor="@color/color_000"
android:textSize="16sp" />
</RelativeLayout>

<View
android:id="@+id/title_line"
android:visibility="gone"
android:layout_width="match_parent"
android:layout_height="2px"
android:background="@color/color_eee" />
</LinearLayout>

/**
* flutter缓存管理,主要是管理多个flutter引擎
**/
class FlutterCacheManager private constructor() {

/**
* 伴生对象,保持单例
*/
companion object {

//喜欢页面,默认是flutter启动的主入口
const val MODULE_NAME_FAVORITE = "main"
//推荐页面
const val MODULE_NAME_RECOMMEND = "recommend"

@JvmStatic
@get:Synchronized
var instance: FlutterCacheManager? = null
get() {
if (field == null) {
field = FlutterCacheManager()
}
return field
}
private set
}

/**
* 空闲时候预加载Flutter
*/
fun preLoad(context: Context){
//在线程空闲时执行预加载任务
Looper.myQueue().addIdleHandler {
initFlutterEngine(context, MODULE_NAME_FAVORITE)
initFlutterEngine(context, MODULE_NAME_RECOMMEND)
false
}
}

/**
* 初始化Flutter
*/
private fun initFlutterEngine(context: Context, moduleName: String): FlutterEngine {
//flutter 引擎
val flutterLoader: FlutterLoader = FlutterInjector.instance().flutterLoader()
val flutterEngine = FlutterEngine(context,flutterLoader, FlutterJNI())
flutterEngine.dartExecutor.executeDartEntrypoint(
DartExecutor.DartEntrypoint(
flutterLoader.findAppBundlePath(),
moduleName
)
)
//存到引擎缓存中
FlutterEngineCache.getInstance().put(moduleName,flutterEngine)
return flutterEngine
}

/**
* 获取缓存的flutterEngine
*/
fun getCachedFlutterEngine(context: Context?, moduleName: String):FlutterEngine{
var flutterEngine = FlutterEngineCache.getInstance()[moduleName]
if(flutterEngine==null && context!=null){
flutterEngine=initFlutterEngine(context,moduleName)
}
return flutterEngine!!
}

}

具体业务类使用


//在app初始化中初始一下
public class MyApplication extends Application {

@Override
public void onCreate() {
super.onCreate();
FlutterCacheManager.getInstance().preLoad(this);
}
}

收藏页面


class FavoriteFragment : FlutterFragment(FlutterCacheManager.MODULE_NAME_FAVORITE) {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
setTitle(getString(R.string.title_favorite))
}
}

推荐页面


class RecommendFragment : FlutterFragment(FlutterCacheManager.MODULE_NAME_RECOMMEND) {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
setTitle(getString(R.string.title_recommend))
}
}

Dart端代码


import 'package:flutter/material.dart';
import 'package:flutter_module/favorite_page.dart';
import 'package:flutter_module/recommend_page.dart';

//至少要有一个入口,而且这下面的man() 和 recommend()函数名字 要和FlutterCacheManager中定义的对应上
void main() => runApp(MyApp(FavoritePage()));

//必须加注解
@pragma('vm:entry-point')
void recommend() => runApp(MyApp(RecommendPage()));

class MyApp extends StatelessWidget {
final Widget page;
const MyApp(this.page);

@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: Scaffold(
body: page,
),
);
}
}

Dart侧收藏页面


import 'package:flutter/material.dart';

class FavoritePage extends StatefulWidget {
@override
_FavoritePageState createState() => _FavoritePageState();
}

class _FavoritePageState extends State<FavoritePage> {
@override
Widget build(BuildContext context) {
return Container(
child: Text("收藏"),
);
}
}

Dart侧推荐页面


import 'package:flutter/material.dart';

class RecommendPage extends StatefulWidget {
@override
_RecommendPageState createState() => _RecommendPageState();
}

class _RecommendPageState extends State<RecommendPage> {
@override
Widget build(BuildContext context) {
return Container(
child: Text("推荐"),
);
}
}

最终效果


image


image


作者:Coolbreeze
链接:https://juejin.cn/post/7005562586843906085
来源:掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

0 个评论

要回复文章请先登录注册