当我们编写flutter程序时候经常会遇到要集成ios或者android sdk。其中android有些sdk不是jar而是aar。如果直接集成打包会是正常的,但是为了结构清晰我们一般会把这些功能单独用一个flutter plugin去集成。然后我们的flutter application再依赖这个plugin。当问我们去编写flutter plugin的时候会出现以下错误。
- 用android studio打开plugin项目的android文件夹会发现里面的java/kotlin文件的import都是灰色。里面的方法或者参数都是红色。这是因为插件没有识别到flutter的sdk。(由于plugin最终是会被application去依赖,所以项目编译是可以通过的不会报错)。这时我们只需在build.gradle文件的末尾添加以下内容
//读取配置
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所以不会参与编译。这项文件就不再试红色了。
- 编译时候出现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
这时候你看下你依赖aar的模式implementation fileTree(includes: [".aar"],dir:"libs"),implementation表示的是依赖只作用在本项目并参与编译。如果你是在flutter application中这么用是不会报错的。但是这是flutter pluigin。每个flutter plugin会编译成一个aar。相当于你把一个aar又编译进了另一个aar当然会报错。所以你这里要换成compileOnly fileTree(includes: [".aar"],dir:"libs")。这样就可以编译通过了。
- 当编译通过后你在使用到这个aar中的内容时候又会报以下错误
Caused by: java.lang.ClassNotFoundException: Didn't find class "XXXXXXX" on path: DexPathList[[zip file "/data/app/~~LmWMF6d-aNOCfQQ32bhOsQ==/
内容可能和我的不一样,但是意思是一样的。就是找不到这个aar中的类。这是为什么因为你用的是compileOnly没有吧aar编译进去。当然会找不到。那么如何去解决?我网上找了很久很多答案都不行。最终自己折腾了出来,方法有两个
- 直接暴力 用rar解压工具把aar解压了。把其中的jar包复制到android文件夹下的libs文件夹内。把complieOnly改成implementation。这个方法的思路是aar无法编译进aar如果是jar肯定是可以的。但是这个方法有个小问题。如果aar包中有些其他设置会丢失。你需要手动加入到你的项目中比如AndroidManifest.xml文件里的配置,权限设定等。自己加入到自己插件项目的文件内就行。
- 通过脚本把aar复制到依赖此插件的主项目中,不参与插件的编译。方法如下
1、 把aar复制到插件的android/libs文件夹中
2、 在插件的android目录的根部(和src同级)新建aar_tools.gradle文件。
3、 在文件内写入以下内容
- 通过脚本把aar复制到依赖此插件的主项目中,不参与插件的编译。方法如下
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()
}
}
//把aar拷贝进入主项目的方法 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',并确保这个文件中对aar的依赖是compileOnly
apply plugin: 'com.android.library'
apply from: './aar_tools.gradle'
...
//省略部分内容
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")
}
修改完之后愉快的编译吧。