Android Native 项目集成Flutter Module

373 阅读3分钟

「这是我参与2022首次更文挑战的第7天,活动详情查看:2022首次更文挑战

首先创建一个Android原生项目,然后可以选择直接创建一个Flutter Project (选择Flutter Module),也可以直接创建一个 New Module(选择Flutter Module)。前者是需要自己手动在Android项目中依赖的,后者则是直接依赖在当前Android项目中的。新手建议后者。

参考google官方中文文档如下:
flutter.cn/docs/develo…

一、准备工作:

1.创建一个Android原生项目

2.创建一个Flutter module

二、采用aar方式集成Flutter module到Android原生

1.执行命令 flutter build aar 成功之后打印如下日志

`Consuming the Module`

`1``. Open <host>\app\build.gradle`

`2``. Ensure you have the repositories configured, otherwise add them:`

`String storageUrl = System.env.FLUTTER_STORAGE_BASE_URL ?: ``"[https://storage.googleapis.com"](https://storage.googleapis.com/)`

`repositories {`

`maven {`

`url ``'E:\anima_demo\build\host\outputs\repo'`

`}`

`maven {`

`url ``"$storageUrl/download.flutter.io"`

`}`

`}`

`3``. Make the host app depend on the Flutter module:`

`dependencies {`

`debugImplementation ``'com.example.anima_demo:flutter_debug:1.0'`

`profileImplementation ``'com.example.anima_demo:flutter_profile:1.0'`

`releaseImplementation ``'com.example.anima_demo:flutter_release:1.0'`

`}`

`4``. Add the `profile` build type:`

`android {`

`buildTypes {`

`profile {`

`initWith debug`

`}`

`}`

`}`


上面的操作是在app下的build.gradle下面配置本地仓库和远程仓库。我试验的结果来看,似乎只有本地仓库会生效。

三、采用源码依赖Flutter Module到Android原生

1.把Android原生项目和Flutter项目放到同一目录下。

2.在Android原生的setting.gradle中做如下设置

// Include the host app project.
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
))      

3.在Android中添加如下依赖

dependencies {
  implementation project(':flutter')
}
四、总结两种依赖的优缺点

1.采用aar方式依赖。优点是原生不需要配置flutter开发环境。缺点是每次修改打包验证都需要重新打出aar包,如果是本地依赖还需要把结果物体给其他同事。远程依赖可能需要上传到自己的maven仓库。

2.采用源码方式依赖。优点是每次其他同事修改,只需要在module中点击pub get 或者 pub update即可更新。缺点是开发原生同事也需要配置flutter开发环境。

个人看法:Flutter开发,能够统一 两个端界面和逻辑的一致性,一份代码两个平台运行,可以提高整体的开发效率。所以原生开发可以学习下Flutter。最好还是采用源码依赖方式,这样多人合作开发Flutter效率会很高。

  • 把flutter页面显示到原生中
一、在首页直接显示Flutter页面,直接把MainActivity继承io.flutter.embedding.android.FlutterActivity,这个包下是最新的FlutterActivity。
package com.example.nativeandflutterdemo

import android.os.Bundle
import io.flutter.embedding.android.FlutterActivity

class MainActivity : FlutterActivity() {

   override fun onCreate(savedInstanceState: Bundle?) {
       super.onCreate(savedInstanceState)
       setContentView(R.layout.activity_main)
   }
}
二、首页是原生的Activity ,在里面点击按钮在跳转到Flutter界面。

startActivity(Intent(this@MainActivity,FlutterActivity::class.java))
或者startActivity(FlutterActivity.createDefaultIntent(this))
需要注意的是一定要在AndroidManifest里面注册FlutterActivity

<activity android:name="io.flutter.embedding.android.FlutterActivity"/>
 
package com.example.nativeandflutterdemo

import android.content.Intent
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.widget.TextView
import io.flutter.embedding.android.FlutterActivity

class MainActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        var tv = findViewById<TextView>(R.id.tv)
        tv.setOnClickListener {
//          startActivity(FlutterActivity.createDefaultIntent(this))
            startActivity(Intent(this@MainActivity,FlutterActivity::class.java))
        }
    }
}
三、当有多个flutter页面的时候,需要从原生跳转到特定flutter页面
  • 先创建两个flutter界面
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';

class OnePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(),
      body: Center(
        child: Text('这是 One 页面'),
      ),
    );
  }
}
import 'package:flutter/cupertino.dart';

class TwoPage extends StatelessWidget{
  @override
  Widget build(BuildContext context) {
    return Container(child: Text("two Page"),);
  }

}
  • 在main.dart中的MaterialApp中添加routes,注册路由。
class MyApp extends StatelessWidget {
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        // This is the theme of your application.
        //
        // Try running your application with "flutter run". You'll see the
        // application has a blue toolbar. Then, without quitting the app, try
        // changing the primarySwatch below to Colors.green and then invoke
        // "hot reload" (press "r" in the console where you ran "flutter run",
        // or press Run > Flutter Hot Reload in a Flutter IDE). Notice that the
        // counter didn't reset back to zero; the application is not restarted.
        primarySwatch: Colors.blue,
      ),
      home: MyHomePage(title: 'Flutter Demo Home Page'),
      routes: {
        "onePage": (context){
          return OnePage();
        },
        "twoPage":(context){
          return TwoPage();
        }
      },
    );
  }
}
  • MainActivity的跳转也需要修改一下
startActivity(FlutterActivity.withNewEngine()
                .initialRoute("twoPage")
                .build(this))

到此为止,Native跳转到原生就结束了。不过发现跳转会有黑屏,因为FlutterActivity创建会启动FlutterEngine。所以尽量少创建FlutterActivity。然后可以对FlutterEngine进行缓存。

  • 在Android 项目的Application中创建引擎(FlutterEngine)
class MyApplication : Application() {
    lateinit var flutterEngine: FlutterEngine

    override fun onCreate() {
        super.onCreate()
        flutterEngine = FlutterEngine(this)
        flutterEngine.dartExecutor.executeDartEntrypoint(
            DartExecutor.DartEntrypoint.createDefault()
        )
        FlutterEngineCache
            .getInstance()
            .put("engine_id", flutterEngine)
    }
}
  • 使用的时候通过缓存来获取引擎
startActivity(
    FlutterActivity
        .withCachedEngine("engine_id")
        .build(this)
)