Flutter插件中引用aar

背景

最近需要制作一个基于aar的Flutter插件,但遇到了一些问题。 我们假设插件名称叫作my_plugin。以前我的解决方案是把aar文件导入my_plugin/android/libs中,然后在my_plugin/android/build.gradle做如下修改:

grovvy 复制代码
rootProject.allprojects {
    repositories {
        google()
        jcenter()
        flatDir {
            dirs project(':my_plugin').file('libs')
        }
    }
}

dependencies {
    implementation fileTree(include: ['*.aar'], dir: 'libs')
}

但我很快发现,这条路现在行不通:

sql 复制代码
Execution failed for task 'xxxx'.
> 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: 
______.aar

很快我又换了一个姿势,同样使用flatDir,但这次我改用了compileOnly

scss 复制代码
```groovy
rootProject.allprojects {
    repositories {
        google()
        mavenCentral()
        flatDir {
            dirs project(':my_plugin').file('libs')
        }
    }
}

dependencies {
    compileOnly fileTree(include: ['*.aar'], dir: 'libs')
}

但也引起了一个小小的麻烦,这种方式需要在宿主app中把aar文件再次导入到对应的libs文件下,然后又要在build.gradle中添加 implementation fileTree(include: ['*.aar'], dir: 'libs')。对于使用者来说不友好,而且flatDir这种形式官方其实是不太推荐的(你会在控制台看到一些警告)。所以怎么相对优雅地解决这个问题?最快的方法当然是发布到远程maven之类的仓库了。谁都能想得到,但很实际开发中并不具备发布到远程maven的条件。

既然远程maven不行,那本地的maven是不是就可以了?

姿势一

第一种方式是直接借用maven-publish插件了。在my_plugin/android/build.gradle写点代码:

groovy 复制代码
//define this
String mavenLocalPath = project(":my_plugin").mkdir("m2repository").absolutePath


rootProject.allprojects {
    repositories {
        google()
        mavenCentral()
        maven {
            url mavenLocalPath
        }
    }
}


//apply plugin
apply plugin: "maven-publish"


publishing {
  publications {
    release(MavenPublication) {
            groupId = 'com.my-company'
            artifactId = 'my-library'
            version = '1.0'
            artifact "path/to/aar"
    }
  }
  repositories {
    maven {
      name = 'myrepo'
      url = mavenLocalPath
    }
  }
}

dependencies {
    implementation "com.my-company:my-library:1.0"
}

然后使用gradle运行publish任务即可:

shell 复制代码
./gradlew publish

//or 
gradle publish

然后你会发现在my_plugin/m2repository目录下生成了相关文件,大功告成!当有新版本时,我们只需再次publish即可。

姿势二

第一种方是借用了maven-publish插件,当然我们也可以手搓一个类似功能的,假设我们把aar放到了my_plugin/android/libs下:

groovy 复制代码
import java.security.MessageDigest
import java.security.NoSuchAlgorithmException

//define this
String mavenLocalPath = project(":my_plugin").mkdir("m2repository").absolutePath


rootProject.allprojects {
    repositories {
        google()
        mavenCentral()
        maven {
            url mavenLocalPath
        }
    }
}

task useAar {
    File file = project.file("libs")
    if (file.exists() && file.isDirectory()) {
        file.listFiles(new FileFilter() {
            @Override
            boolean accept(File pathname) {
                return pathname.name.endsWith(".aar")
            }
        }).each { item ->
            String aarName = item.name.substring(0, item.name.length() - 4)
            String[] aarInfo = aarName.split("-")
            String sha1 = getFileSha1(item)
            String md5 = getFileMD5(item)
            String fromStr = item.path
            String intoStr = aarPath + "/" + aarInfo[0].replace(".", "/") + "/" + aarInfo[1] + "/" + aarInfo[2]
            String newName = aarInfo[1] + "-" + aarInfo[2] + ".aar"

            project.copy {
                from fromStr
                into intoStr
                rename(item.name, newName)
            }

            project.file(intoStr + "/" + newName + ".md5").write(md5)
            project.file(intoStr + "/" + newName + ".sha1").write(sha1)

            String pomPath = intoStr + "/" + newName.substring(0, newName.length() - 4) + ".pom"
            project.file(pomPath).write(createPomStr(aarInfo[0], aarInfo[1], aarInfo[2]))
            project.file(pomPath + ".md5").write(getFileMD5(project.file(pomPath)))
            project.file(pomPath + ".sha1").write(getFileSha1(project.file(pomPath)))

            String metadataPath = project.file(intoStr).getParentFile().path + "/maven-metadata.xml"
            project.file(metadataPath).write(createMetadataStr(aarInfo[0], aarInfo[1], aarInfo[2]))
            project.file(metadataPath + ".md5").write(getFileMD5(project.file(metadataPath)))
            project.file(metadataPath + ".sha1").write(getFileSha1(project.file(metadataPath)))
            dependencies {
                implementation "${aarInfo[0]}:${aarInfo[1]}:${aarInfo[2]}"
            }
        }
    }
}

public static String createMetadataStr(String groupId, String artifactId, String version) {
    return "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" +
            "<metadata>\n" +
            "  <groupId>$groupId</groupId>\n" +
            "  <artifactId>$artifactId</artifactId>\n" +
            "  <versioning>\n" +
            "    <release>$version</release>\n" +
            "    <versions>\n" +
            "      <version>$version</version>\n" +
            "    </versions>\n" +
            "    <lastUpdated>${new Date().format('yyyyMMdd')}000000</lastUpdated>\n" +
            "  </versioning>\n" +
            "</metadata>\n"
}

public static String createPomStr(String groupId, String artifactId, String version) {
    return "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" +
            "<project xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\" xmlns=\"http://maven.apache.org/POM/4.0.0\"\n" +
            "    xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\">\n" +
            "  <modelVersion>4.0.0</modelVersion>\n" +
            "  <groupId>$groupId</groupId>\n" +
            "  <artifactId>$artifactId</artifactId>\n" +
            "  <version>$version</version>\n" +
            "  <packaging>aar</packaging>\n" +
            "</project>\n"
}

public static String getFileSha1(File file) {
    FileInputStream input = null;
    try {
        input = new FileInputStream(file);
        MessageDigest digest = MessageDigest.getInstance("SHA-1");
        byte[] buffer = new byte[1024 * 1024 * 10];

        int len = 0;
        while ((len = input.read(buffer)) > 0) {
            digest.update(buffer, 0, len);
        }
        String sha1 = new BigInteger(1, digest.digest()).toString(16);
        int length = 40 - sha1.length();
        if (length > 0) {
            for (int i = 0; i < length; i++) {
                sha1 = "0" + sha1;
            }
        }
        return sha1;
    }
    catch (IOException e) {
        System.out.println(e);
    }
    catch (NoSuchAlgorithmException e) {
        System.out.println(e);
    }
    finally {
        try {
            if (input != null) {
                input.close();
            }
        }
        catch (IOException e) {
            System.out.println(e);
        }
    }
}

public static String getFileMD5(File file) {
    FileInputStream input = null;
    try {
        input = new FileInputStream(file);
        MessageDigest digest = MessageDigest.getInstance("MD5");
        byte[] buffer = new byte[1024 * 1024 * 10];

        int len = 0;
        while ((len = input.read(buffer)) > 0) {
            digest.update(buffer, 0, len);
        }
        String md5 = new BigInteger(1, digest.digest()).toString(16);
        int length = 32 - md5.length();
        if (length > 0) {
            for (int i = 0; i < length; i++) {
                md5 = "0" + md5;
            }
        }
        return md5;
    }
    catch (IOException e) {
        System.out.println(e);
    }
    catch (NoSuchAlgorithmException e) {
        System.out.println(e);
    }
    finally {
        try {
            if (input != null) {
                input.close();
            }
        }
        catch (IOException e) {
            System.out.println(e);
        }
    }
}

结束语

当然方式可能有很多,最后我也只用了第一种方式,如果大家有更好的招,欢迎指出~

相关推荐
LawrenceLan14 小时前
Flutter 零基础入门(九):构造函数、命名构造函数与 this 关键字
开发语言·flutter·dart
一豆羹15 小时前
macOS 环境下 ADB 无线调试连接失败、Protocol Fault 及端口占用的深度排查
flutter
行者9615 小时前
OpenHarmony上Flutter粒子效果组件的深度适配与实践
flutter·交互·harmonyos·鸿蒙
行者9617 小时前
Flutter与OpenHarmony深度集成:数据导出组件的实战优化与性能提升
flutter·harmonyos·鸿蒙
小雨下雨的雨18 小时前
Flutter 框架跨平台鸿蒙开发 —— Row & Column 布局之轴线控制艺术
flutter·华为·交互·harmonyos·鸿蒙系统
小雨下雨的雨18 小时前
Flutter 框架跨平台鸿蒙开发 —— Center 控件之完美居中之道
flutter·ui·华为·harmonyos·鸿蒙
小雨下雨的雨19 小时前
Flutter 框架跨平台鸿蒙开发 —— Icon 控件之图标交互美学
flutter·华为·交互·harmonyos·鸿蒙系统
小雨下雨的雨19 小时前
Flutter 框架跨平台鸿蒙开发 —— Placeholder 控件之布局雏形美学
flutter·ui·华为·harmonyos·鸿蒙系统
行者9619 小时前
OpenHarmony Flutter弹出菜单组件深度实践:从基础到高级的完整指南
flutter·harmonyos·鸿蒙
前端不太难20 小时前
Flutter / RN / iOS,在长期维护下的性能差异本质
flutter·ios