當(dāng)我們編寫flutter程序時(shí)候經(jīng)常會(huì)遇到要集成ios或者android sdk爱葵。其中android有些sdk不是jar而是aar。如果直接集成打包會(huì)是正常的甘苍,但是為了結(jié)構(gòu)清晰我們一般會(huì)把這些功能單獨(dú)用一個(gè)flutter plugin去集成灯荧。然后我們的flutter application再依賴這個(gè)plugin纹蝴。當(dāng)問我們?nèi)ゾ帉慺lutter plugin的時(shí)候會(huì)出現(xiàn)以下錯(cuò)誤海铆。
- 用android studio打開plugin項(xiàng)目的android文件夾會(huì)發(fā)現(xiàn)里面的java/kotlin文件的import都是灰色迹恐。里面的方法或者參數(shù)都是紅色。這是因?yàn)椴寮]有識(shí)別到flutter的sdk卧斟。(由于plugin最終是會(huì)被application去依賴殴边,所以項(xiàng)目編譯是可以通過的不會(huì)報(bào)錯(cuò))。這時(shí)我們只需在build.gradle文件的末尾添加以下內(nèi)容
//讀取配置
def localProperties = new Properties()
def localPropertiesFile = rootProject.file('local.properties')
if (localPropertiesFile.exists()) {
localPropertiesFile.withReader('UTF-8') {
reader-> localProperties.load(reader)
}
}
//獲取flutter sdk路徑
def flutterRoot = localProperties.getProperty('flutter.sdk')
if(flutterRoot == null) {
throw new GradleException('Flutter sdk not found.')
}
dependencies {
compileOnly files("$flutterRoot/bin/cache/artifacts/engine/android-arm/flutter.jar")
compileOnly("androidx.annotation:annotation:1.0.0")
}
上面這段腳本是用來依賴flutter.jar 以及annotation的珍语。用的是complieOnly所以不會(huì)參與編譯锤岸。這項(xiàng)文件就不再試紅色了。
- 編譯時(shí)候出現(xiàn)Error while evaluating property 'hasLocalAarDeps' of task ':xxxx插件名:bundleDebugAar'
Direct local .aar file dependencies are not supported when building an AAR. The resulting AAR would be broken because the classes and Android resources from any local .aar file dependencies would not be packaged in the resulting AAR.Previous versions of the Android Gradle Plugin produce broken AARs in this case too (despite not throwing this error). The following direct local .aar file dependencies of the :xxxx project caused this error: xxxxx\xxxx\xxxx.aar
這時(shí)候你看下你依賴aar的模式implementation fileTree(includes: [".aar"],dir:"libs")廊酣,implementation表示的是依賴只作用在本項(xiàng)目并參與編譯能耻。如果你是在flutter application中這么用是不會(huì)報(bào)錯(cuò)的赏枚。但是這是flutter pluigin亡驰。每個(gè)flutter plugin會(huì)編譯成一個(gè)aar晓猛。相當(dāng)于你把一個(gè)aar又編譯進(jìn)了另一個(gè)aar當(dāng)然會(huì)報(bào)錯(cuò)。所以你這里要換成compileOnly fileTree(includes: [".aar"],dir:"libs")凡辱。這樣就可以編譯通過了戒职。
- 當(dāng)編譯通過后你在使用到這個(gè)aar中的內(nèi)容時(shí)候又會(huì)報(bào)以下錯(cuò)誤
Caused by: java.lang.ClassNotFoundException: Didn't find class "XXXXXXX" on path: DexPathList[[zip file "/data/app/~~LmWMF6d-aNOCfQQ32bhOsQ==/
內(nèi)容可能和我的不一樣,但是意思是一樣的透乾。就是找不到這個(gè)aar中的類洪燥。這是為什么因?yàn)槟阌玫氖莄ompileOnly沒有吧aar編譯進(jìn)去。當(dāng)然會(huì)找不到乳乌。那么如何去解決捧韵?我網(wǎng)上找了很久很多答案都不行。最終自己折騰了出來汉操,方法有兩個(gè)
- 直接暴力 用rar解壓工具把a(bǔ)ar解壓了再来。把其中的jar包復(fù)制到android文件夾下的libs文件夾內(nèi)。把complieOnly改成implementation磷瘤。這個(gè)方法的思路是aar無法編譯進(jìn)aar如果是jar肯定是可以的芒篷。但是這個(gè)方法有個(gè)小問題。如果aar包中有些其他設(shè)置會(huì)丟失采缚。你需要手動(dòng)加入到你的項(xiàng)目中比如AndroidManifest.xml文件里的配置针炉,權(quán)限設(shè)定等。自己加入到自己插件項(xiàng)目的文件內(nèi)就行扳抽。
- 通過腳本把a(bǔ)ar復(fù)制到依賴此插件的主項(xiàng)目中篡帕,不參與插件的編譯。方法如下
1贸呢、 把a(bǔ)ar復(fù)制到插件的android/libs文件夾中
2赂苗、 在插件的android目錄的根部(和src同級(jí))新建aar_tools.gradle文件。
3贮尉、 在文件內(nèi)寫入以下內(nèi)容
- 通過腳本把a(bǔ)ar復(fù)制到依賴此插件的主項(xiàng)目中篡帕,不參與插件的編譯。方法如下
import java.util.zip.ZipEntry
import java.util.zip.ZipFile
// 拷貝aar的方法
static aarFileCopy(String srcPath,String desPath) {
System.out.println("copy aar from <<${srcPath}>> to <<${desPath}>>")
try {
FileInputStream fis = new FileInputStream(srcPath)
FileOutputStream fos = new FileOutputStream(desPath)
byte[] data = new byte[1024*8]
int len = 0
while ((len = fis.read(data))!=-1) {
fos.write(data,0,len)
}
fis.close()
fos.close()
}catch(Exception e) {
e.printStackTrace()
}
}
//把a(bǔ)ar拷貝進(jìn)入主項(xiàng)目的方法 com.example.android_control換成你自己的插件名
copyAar2Host('com.example.android_control')
void copyAar2Host(String pluginGroup) {
Project currentProject = null
Project appProject = null
rootProject.allprojects.each {
p->
boolean isApp = p.plugins.hasPlugin("com.android.application")
println("<<${p.name}>> isHost ? ${isApp}")
if (p.group == pluginGroup) {
currentProject = p
println("Plugin project name is $currentProject")
}
if(isApp) {
appProject = p
println("Host project name is <<${p.name}>>")
}
}
Set<File> aarFiles = new HashSet<File>()
if (appProject != null && currentProject != null) {
File libs = new File("${currentProject.projectDir}","libs")
if(libs.isDirectory()) {
libs.listFiles().each {
f->
if(f.name.endsWith(".aar")) {
println("The aar file name to be copied is <<${f.name}>>")
aarFiles.add(f)
}
}
}
if (!aarFiles.isEmpty()) {
File applibs = new File("${appProject.projectDir}${File.separator}libs")
if(!applibs.isDirectory()) {
applibs.mkdirs()
}
aarFiles.each {
f->
File copyAar = new File("${appProject.projectDir}${File.separator}libs",f.name)
if(!copyAar.exists()) {
copyAar.createNewFile()
aarFileCopy(f.path,copyAar.path)
} else {
}
}
appProject.dependencies {
implementation fileTree(dir:"${appProject.projectDir}${File.separator}libs",include:["*.jar","*.aar"])
}
}
}
}
repositories{
flatDir {
dirs 'libs'
}
}
- 4拌滋、在插件的android build.gradle文件的以apply plugin: 'com.android.library'下一行位置插入apply from: './aar_tools.gradle',并確保這個(gè)文件中對(duì)aar的依賴是compileOnly
apply plugin: 'com.android.library'
apply from: './aar_tools.gradle'
...
//省略部分內(nèi)容
dependencies {
// compileOptions files('libs/SdkApiJar-V1.0.0.221128.0.aar')
// provided files('libs/SdkApiJar-V1.0.0.221128.0.aar.aar')
compileOnly fileTree(includes: ["*.aar"],dir:"libs")
compileOnly files("$flutterRoot/bin/cache/artifacts/engine/android-arm/flutter.jar")
compileOnly("androidx.annotation:annotation:1.0.0")
}
修改完之后愉快的編譯吧猜谚。