今日,公司下達(dá)任務(wù),需要使用Flutter進(jìn)行項(xiàng)目開(kāi)發(fā),以下是實(shí)戰(zhàn)中遇到的一些坑,以及解決辦法。
一、Flutter強(qiáng)制使用Android Grade Plugin 8.0(以下簡(jiǎn)稱AGP8.0)
由于我們采用的是Flutter3.24.0,而Flutter3.10.0 開(kāi)始就強(qiáng)制使用AGP8.0

那么AGP8.0會(huì)帶來(lái)什么變化呢?
1、ButterKnife不能使用(改動(dòng)是巨大的);
2、Greendao需要升級(jí)到3.3.1
classpath 'org.greenrobot:greendao-gradle-plugin:3.3.1' // add plugin
并在app/build.gradle增加如下腳本
afterEvaluate {
tasks.named('compileDebugKotlin') {
dependsOn(tasks.named('greendao'))
}
// 如果還有其他變體
tasks.named('compileReleaseKotlin') {
dependsOn(tasks.named('greendao'))
}
tasks.named('compileReleaseApiKotlin') {
dependsOn tasks.named('greendao')
}
}
3、如果AGP不升級(jí),flutter混合開(kāi)發(fā)會(huì)直接無(wú)法編譯,報(bào)錯(cuò)如下
A problem occurred evaluating settings 'AiTeacher'.
> Could not find method includeBuild() for arguments [/Users/yanjunhui/Library/flutter/packages/flutter_tools/gradle] on object of type org.gradle.plugin.management.internal.DefaultPluginManagementSpec.
* Try:
Run with --info or --debug option to get more log output. Run with --scan to get full insights.
* Exception is:
...
Caused by: org.gradle.internal.metaobject.AbstractDynamicObject$CustomMessageMissingMethodException: Could not find method includeBuild() for arguments [/Users/yanjunhui/Library/flutter/packages/flutter_tools/gradle] on object of type org.gradle.plugin.management.internal.DefaultPluginManagementSpec.
at org.gradle.internal.metaobject.AbstractDynamicObject$CustomMissingMethodExecutionFailed.<init>(AbstractDynamicObject.java:190)
at org.gradle.internal.metaobject.AbstractDynamicObject.methodMissingException(AbstractDynamicObject.java:184)
at org.gradle.internal.metaobject.ConfigureDelegate.invokeMethod(ConfigureDelegate.java:86)
at include_flutter$_run_closure2.doCall(include_flutter.groovy:31)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at org.gradle.util.ClosureBackedAction.execute(ClosureBackedAction.java:71)
at org.gradle.util.ConfigureUtil.configureTarget(ConfigureUtil.java:154)
at org.gradle.util.ConfigureUtil.configure(ConfigureUtil.java:105)
at org.gradle.util.ConfigureUtil$WrappedConfigureAction.execute(ConfigureUtil.java:166)
at org.gradle.initialization.DefaultSettings.pluginManagement(DefaultSettings.java:319)
at org.gradle.initialization.DefaultSettings_Decorated.pluginManagement(Unknown Source)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at org.gradle.internal.metaobject.BeanDynamicObject$MetaClassAdapter.invokeMethod(BeanDynamicObject.java:484)
at org.gradle.internal.metaobject.BeanDynamicObject.tryInvokeMethod(BeanDynamicObject.java:196)
at org.gradle.internal.metaobject.CompositeDynamicObject.tryInvokeMethod(CompositeDynamicObject.java:98)
at org.gradle.internal.extensibility.MixInClosurePropertiesAsMethodsDynamicObject.tryInvokeMethod(MixInClosurePropertiesAsMethodsDynamicObject.java:34)
at org.gradle.groovy.scripts.BasicScript$ScriptDynamicObject.tryInvokeMethod(BasicScript.java:134)
at org.gradle.internal.metaobject.AbstractDynamicObject.invokeMethod(AbstractDynamicObject.java:163)
at org.gradle.groovy.scripts.BasicScript.invokeMethod(BasicScript.java:83)
at include_flutter.run(include_flutter.groovy:30)
at settings_2oj8v4nfyj4xpg1mfule98gaa.run(/Users/yanjunhui/android/AiTeacher/AiTeacher/settings.gradle:14)
at org.gradle.groovy.scripts.internal.DefaultScriptRunnerFactory$ScriptRunnerImpl.run(DefaultScriptRunnerFactory.java:91)
... 120 more
二、Flutter與源生之間依賴沖突,導(dǎo)致打包成maven-aar無(wú)法添加依賴
flutter_sound(音頻庫(kù)) 、video_player(視頻庫(kù)) 其底層依賴了androidx.media,實(shí)際上與英趣的依賴是有沖突的,無(wú)法通過(guò)編譯


而且神奇的是,如果是通過(guò)flutter源碼形式的編譯是可以通過(guò)的,但是那樣的話會(huì)有以下弊端。
1、以后諸位android開(kāi)發(fā)都需要將flutter源碼拉取到本地,并且及時(shí)同步,否則項(xiàng)目將無(wú)法編譯;
2、可能和我一樣,面臨無(wú)法開(kāi)啟調(diào)試的窘境(不知是何原因,我目前英趣只要和flutter源碼混合編譯,就無(wú)法調(diào)試);
3、以后的項(xiàng)目結(jié)構(gòu)將會(huì)和如下截圖一樣,影響美觀。

而正常情況下是這樣子的

所以以上庫(kù)包含的功能,最終都通過(guò)橋接的方式讓源生實(shí)現(xiàn)了,并且flutter端都做了注解和警告

好了,以上主要是源生方面踩的坑,下面就開(kāi)始講一講Flutter代碼一些踩過(guò)的坑,全是干貨。
Flutter端的坑
一、FlutterEngine之間相互獨(dú)立
看看獨(dú)立的定義
1、獨(dú)立的數(shù)據(jù);
2、獨(dú)立的ui;
3、獨(dú)立的plugin;
4、獨(dú)立的methodChannel;
那么會(huì)帶來(lái)哪些問(wèn)題呢
1、flutter中不同F(xiàn)lutterEngine數(shù)據(jù)不能共享;
2、所有ui需要單獨(dú)綁定;
3、所有plugin需要單獨(dú)綁定;
4、所有methodChannel需要單獨(dú)綁定;
那么通俗一點(diǎn)來(lái)講就是,你從Android開(kāi)發(fā)的FlutterActivityA 跳轉(zhuǎn)到 FlutterActivityB 的時(shí)候,保存在flutter端的代碼是不能傳遞的,神奇吧?它只能通過(guò)Arguments攜帶少量參數(shù),那如果我們需要傳遞的數(shù)據(jù)量很大,該怎么辦?GPT建議將數(shù)據(jù)保存在源生,通過(guò)MethodChannel獲?。?br> Flutter頁(yè)面就像是網(wǎng)頁(yè)一樣,從A跳到B時(shí),載體是不能變化的。如果需要變化,那么引擎是不能復(fù)用的,復(fù)用引擎會(huì)導(dǎo)致界面加載異常。不復(fù)用引擎會(huì)導(dǎo)致數(shù)據(jù)異常。所以如果有這種需求,需要修改設(shè)計(jì),將數(shù)據(jù)保存在源生。
ListView莫名奇妙頂部多了一段空間

如圖,我們期望的是

幾經(jīng)嘗試,原因如下

這兩個(gè)值在android經(jīng)常拿到的是0
MediaQuery.of(context).padding.top
MediaQuery.of(context).padding.bottom