android 工程集成Flutter
集成方式主要是两种
1、 工程的方式集成
首先创建android,和flutter工程,工程路径必须在同一路径下:
1、在android 工程的settings.gradle 文件中添加:
rootProject.name = "flutterDemo"
include ':app'
// 添加如下代码
setBinding(new Binding([gradle: this]))
evaluate(new File(
settingsDir,
'../flutter_module/.android/include_flutter.groovy'
))
2、app的 build.gradle
dependencies {
implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
implementation 'androidx.core:core-ktx:1.3.1'
implementation 'androidx.appcompat:appcompat:1.2.0'
implementation 'com.google.android.material:material:1.2.1'
implementation 'androidx.constraintlayout:constraintlayout:2.0.1'
// 添加依赖
implementation project(path: ':flutter')
testImplementation 'junit:junit:4.+'
androidTestImplementation 'androidx.test.ext:junit:1.1.2'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0'
}
3、 清单文件 ndroidManifest.xml 中添加
集成完,如下所示:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.flutterdemo">
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.FlutterDemo">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<!-- 添加activity -->
<activity
android:name="io.flutter.embedding.android.FlutterActivity"
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
android:hardwareAccelerated="true"
android:theme="@style/Theme.FlutterDemo"
android:windowSoftInputMode="adjustResize" >
</activity>
</application>
</manifest>
4、 添加跳转测试:
package com.example.flutterdemo
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.view.View
import io.flutter.embedding.android.FlutterActivity
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
findViewById<View>(R.id.btn).setOnClickListener {
var intent = FlutterActivity.createDefaultIntent(MainActivity@ this)
startActivity(intent)
}
}
}
5、 集成完后效果:
2、 aar方式集成
1、使用命令build aar : flutter build aar
qitmac000903@MacBook-Pro-3 flutter_module % flutter build aar
💪 Building with sound null safety 💪
Running Gradle task 'assembleAarDebug'... 7.4s
✓ Built build/host/outputs/repo.
Running Gradle task 'assembleAarProfile'... 32.3s
✓ Built build/host/outputs/repo.
Running Gradle task 'assembleAarRelease'... 27.8s
✓ Built build/host/outputs/repo.
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"
repositories {
maven {
url '/Users/qitmac000903/Desktop/work/flutter_module/build/host/outputs/repo'
}
maven {
url "$storageUrl/download.flutter.io"
}
}
3. Make the host app depend on the Flutter module:
dependencies {
debugImplementation 'com.flutter_module:flutter_debug:1.0'
profileImplementation 'com.flutter_module:flutter_profile:1.0'
releaseImplementation 'com.flutter_module:flutter_release:1.0'
}
4. Add the `profile` build type:
android {
buildTypes {
profile {
initWith debug
}
}
}
2、下面就是集成步骤
在工程build.gradle目录下添加:
// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript {
ext.kotlin_version = "1.5.0"
repositories {
google()
mavenCentral()
}
dependencies {
classpath "com.android.tools.build:gradle:4.2.1"
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
}
}
allprojects {
repositories {
google()
mavenCentral()
jcenter() // Warning: this repository is going to shut down soon
maven {
url '/Users/qitmac000903/Desktop/work/flutter_module/build/host/outputs/repo'
}
maven {
url "http://download.flutter.io"
}
}
}
task clean(type: Delete) {
delete rootProject.buildDir
}
3、app 的build.grable 添加:
dependencies {
//添加依赖
debugImplementation 'com.flutter_module:flutter_debug:1.0'
profileImplementation 'com.flutter_module:flutter_profile:1.0'
releaseImplementation 'com.flutter_module:flutter_release:1.0'
}
4、添加 profile编译类型
buildTypes {
profile {
initWith debug
}
}
完成的文件为:
plugins {
id 'com.android.application'
id 'kotlin-android'
}
android {
compileSdkVersion 32
buildToolsVersion "30.0.3"
defaultConfig {
.........
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
kotlinOptions {
jvmTarget = '1.8'
}
// 添加 profile编译类型
buildTypes {
profile {
initWith debug
}
}
}
dependencies {
..........
//添加依赖
debugImplementation 'com.flutter_module:flutter_debug:1.0'
profileImplementation 'com.flutter_module:flutter_profile:1.0'
releaseImplementation 'com.flutter_module:flutter_release:1.0'
}
其他步骤和,工程集成的,3,4,5 一致
android 原生展示Flutter:
主要方式有是3种:
1、android 开启flutter 页面
2、Fragment开启的方式
3、View的方式展示
android 开启flutter 页面
// 开启默认页面
var intent = FlutterActivity.createDefaultIntent(MainActivity@ this)
// 开启其他页页面
//startActivity(FlutterActivity.withNewEngine().initialRoute("second").build(this))
startActivity(intent)
在这种方式下,发现,开启会非常慢,官方给出的解决方案是engine cache
在application中添加
override fun onCreate() {
super.onCreate()
val flutterEngine = FlutterEngine(this)
flutterEngine.dartExecutor.executeDartEntrypoint(
DartExecutor.DartEntrypoint.createDefault()
)
FlutterEngineCache.getInstance().put("main", flutterEngine)
}
传参问题,官方没有相关解决方案,那么只能从route上想办法
类似:
startActivity(FlutterActivity.withNewEngine().initialRoute("second?text=second test").build(this))
但是这种做不到快速启动 ,如果想快速启动+ 启动传参,可以使用闲鱼开放的flutter混合框架 —— flutter-boost,就可以很轻松的实现native携参打开flutter页面
Fragment开启的方式
代码案例:
val fragmentManager: FragmentManager = supportFragmentManager
flutterFragment = fragmentManager.findFragmentByTag(TAG_FLUTTER_FRAGMENT) as FlutterFragment?
if (flutterFragment == null) {
flutterFragment = FlutterFragment.createDefault()
fragmentManager
.beginTransaction()
.add(
R.id.container_fragment,
flutterFragment!!,
TAG_FLUTTER_FRAGMENT
)
.commit()
}
使用缓存,更快的打开:(同样需要,在application中添加 缓存)
val fragmentManager: FragmentManager = supportFragmentManager
flutterFragment = fragmentManager.findFragmentByTag(TAG_FLUTTER_FRAGMENT) as FlutterFragment?
if (flutterFragment == null) {
flutterFragment = FlutterFragment.withCachedEngine("main").build()
fragmentManager
.beginTransaction()
.add(
R.id.container_fragment,
flutterFragment!!,
TAG_FLUTTER_FRAGMENT
)
.commit()
}
View的开启的方式
官方说明
官方demo
使用起来还是有些费劲的,不多说,直接上代码:
val flutterView = FlutterView(ViewActivity@this)
val lp: FrameLayout.LayoutParams = FrameLayout.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.MATCH_PARENT
)
val engine = FlutterEngine(applicationContext)
engine.dartExecutor.executeDartEntrypoint(
DartExecutor.DartEntrypoint.createDefault()
)
var flutterViewEngine = FlutterViewEngine(engine)
flutterViewEngine.attachToActivity(this)
flutterViewEngine.attachFlutterView(flutterView)
val flContainer: FrameLayout = findViewById(R.id.container_view)
flContainer.addView(flutterView, lp)
其中使用的 FlutterViewEngine可以复制到自己的工程中
Flutter 和Native通信
通信方式
通信方式 | 双向通信 | 有返回值 | 持续通信 |
---|---|---|---|
BasicMessageChannel | ✓ | ✓ | ✓ |
MethodChannel | ✓ | ✓ | ✗ |
EventChannel | ✗ | ✓ | ✓ |
BasicMessageChannel 使用 :
android 端:
// 定义message channel
private final BasicMessageChannel<String> messageChannel;
// 创建
// messager = flutterEngine.getDartExecutor().getBinaryMessenger()
messageChannel = new BasicMessageChannel(messenger, "BasicMessageChannelPlugin", StringCodec.INSTANCE);
// 发送消息
messageChannel.send(message, callback);
// 接收消息
messageChannel.setMessageHandler(new BasicMessageChannel.MessageHandler<String>() {
@Override
public void onMessage(@Nullable @org.jetbrains.annotations.Nullable String message, @NonNull @NotNull BasicMessageChannel.Reply<String> reply) {
}
});
- BinaryMessenger messenger - 消息信使,是消息的发送与接收的工具;
- String name - Channel的名字,也是其唯一标识符和Flutter端对应(和效果图(1.1)对应)
- MessageCodec codec - 消息的编解码器,他有如下表格类型
Flutter端代码
// 创建 BasicMessageChannel
BasicMessageChannel<String> _basicMessageChannel = BasicMessageChannel('BasicMessageChannelPlugin', StringCodec());
//使用BasicMessageChannel接受来自Native的消息,并向Native回复
_basicMessageChannel.setMessageHandler((String? message) => Future<String>(() {
setState(() {
//Android --> Flutter
_basicMessage = 'BasicMessageChannel:' + message!;
});
return "BasicMessageChannel收到android的消息:" + message!;
}));
// 发送消息:
response = await _basicMessageChannel.send(value);
MethodChannel 使用 :
用于传递方法调用(method invocation),一次性通信,通常用于Dart调用Native的方法:如拍照;
本次例子,只展示,Dart调用 native
android端代码
// 创建messager
messager = flutterEngine.getDartExecutor()
// 创建 channel
MethodChannel channel = new MethodChannel(messenger, "MethodChannelPlugin");
//接收调用
channel.setMethodCallHandler(new MethodCallHandler() {
@Override
public void onMethodCall(@NonNull @NotNull MethodCall call, @NonNull @NotNull Result result) {
switch (call.method) {//处理来自Dart的方法调用
case "send":
result.success("MethodChannelPlugin收到:" + call.arguments);//返回结果给Dart
break;
default:
result.notImplemented();
}
}
});
Flutter 端代码
// 创建 _methodChannel
MethodChannel _methodChannel = new MethodChannel("MethodChannelPlugin");
// 发送消息,并取到返回值
var content = await _methodChannel.invokeMethod("send", value);
print("szjmethodChannel$content");
EventChannel 使用 :
android调用
// 创建messager
messager = flutterEngine.getDartExecutor()
EventChannel eventChannelPlugin = new EventChannel(messenger, "demo.ht.com.androidproject/EventChannelPlugin");
eventChannelPlugin.setStreamHandler(new EventChannel.StreamHandler() {
@Override
public void onListen(Object arguments, EventChannel.EventSink events) {
events.success("发送返回值");
}
@Override
public void onCancel(Object arguments) {
}
});
Flutter 端调用
// 创建对应的 _eventChannelPlugin
EventChannel _eventChannelPlugin = EventChannel("demo.ht.com.androidproject/EventChannelPlugin");
//使用Event来接收电量消息
_eventChannelPlugin.receiveBroadcastStream().listen((event) {
setState(() {
_eventMessage = event;
});
});
BasicMessageChannel ,MethodChannel,EventChannel 已经封装成了相关的工具,还有 FlutterAppActivity的实现
github地址: https://github.com/junyingzhao001/androidFlutterDemo
参考链接:
Flutter混合开发 BasicMessageChannel与原生android通信(4.3)
Adding a Flutter screen to an Android app