Skip to content

Instantly share code, notes, and snippets.

@xymelon
Created December 20, 2022 11:28
Show Gist options
  • Save xymelon/5f199d4b2166885ecc349e1fe1ab7c99 to your computer and use it in GitHub Desktop.
Save xymelon/5f199d4b2166885ecc349e1fe1ab7c99 to your computer and use it in GitHub Desktop.
// This script is used to initialize the build in a module or plugin project.
// During this phase, the script applies the Maven plugin and configures the
// destination of the local repository.
// The local repository will contain the AAR and POM files.
// 基于flutter sdk 3.3.10 aar_init_script.gradle修改(位于packages/flutter_tools/gradle/目录下)
// 1、支持上传本地或远程maven仓库(包括自身和依赖的插件库)
// 2、支持flutter插件依赖库版本号(以插件依赖库中pubspec.yaml#version为准),并校验maven库中是否存在,避免重复上传maven仓库报错
import java.nio.file.Paths
// 改动:新增maven相关参数、版本号
void configureProject(Project project, String mavenUrl, String mavenUser, String mavenPwd, String version) {
if (!project.hasProperty("android")) {
throw new GradleException("Android property not found.")
}
if (!project.android.hasProperty("libraryVariants")) {
throw new GradleException("Can't generate AAR on a non Android library project.");
}
// 改动:参数非空校验
if (mavenUrl == null || mavenUrl.isEmpty()) {
throw new GradleException("mavenUrl参数为空")
}
// Snapshot versions include the timestamp in the artifact name.
// Therefore, remove the snapshot part, so new runs of `flutter build aar` overrides existing artifacts.
// This version isn't relevant in Flutter since the pub version is used
// to resolve dependencies.
// project.version = project.version.replace("-SNAPSHOT", "")
// if (project.hasProperty("buildNumber")) {
// project.version = project.property("buildNumber")
// }
// 改动:版本号参数传递
project.version = version
if (isLocalMavenRepo(mavenUrl)) {
// 本地路径时,保持原有逻辑
project.version = project.version.replace("-SNAPSHOT", "")
}
project.android.libraryVariants.all { variant ->
addAarTask(project, mavenUrl, variant)
}
project.publishing {
repositories {
maven {
// 改动:支持上传maven仓库(本地仓库不用认证)
url = mavenUrl
if (!isLocalMavenRepo(mavenUrl)) {
credentials {
username = mavenUser
password = mavenPwd
}
}
}
}
}
// Some extra work to have alternative publications with the same format as the old maven plugin.
// Instead of using classifiers for the variants, the old maven plugin appended `_{variant}` to the artifactId
// First, create a default MavenPublication for each variant (except "all" since that is used to publish artifacts in the new way)
project.components.forEach { component ->
if (component.name != "all") {
project.publishing.publications.create(component.name, MavenPublication) {
from component
}
}
}
// then, rename the artifactId to include the variant and make sure to remove any classifier
// data tha gradle has set, as well as adding a <relocation> tag pointing to the new coordinates
project.publishing.publications.forEach { pub ->
def relocationArtifactId = pub.artifactId
pub.artifactId = "${relocationArtifactId}_${pub.name}"
pub.alias = true
pub.pom.distributionManagement {
relocation {
// New artifact coordinates
groupId = "${pub.groupId}"
artifactId = "${relocationArtifactId}"
version = "${pub.version}"
message = "Use classifiers rather than _variant for new publish plugin"
}
}
}
// also publish the artifacts in the new way, using one set of coordinates with classifiers
project.publishing.publications.create("all", MavenPublication) {
from project.components.all
alias false
}
if (!project.property("is-plugin").toBoolean()) {
return
}
String storageUrl = System.getenv('FLUTTER_STORAGE_BASE_URL') ?: "https://storage.googleapis.com"
// This is a Flutter plugin project. Plugin projects don't apply the Flutter Gradle plugin,
// as a result, add the dependency on the embedding.
project.repositories {
maven {
url "$storageUrl/download.flutter.io"
}
}
String engineVersion = Paths.get(getFlutterRoot(project), "bin", "internal", "engine.version")
.toFile().text.trim()
project.dependencies {
// Add the embedding dependency.
compileOnly("io.flutter:flutter_embedding_release:1.0.0-$engineVersion") {
// We only need to expose io.flutter.plugin.*
// No need for the embedding transitive dependencies.
transitive = false
}
}
}
// 改动:新增maven相关参数
void configurePlugin(Project project, String mavenUrl, String mavenUser, String mavenPwd) {
if (!project.hasProperty("android")) {
// A plugin doesn't support the Android platform when this property isn't defined in the plugin.
return
}
configureProject(project, mavenUrl, mavenUser, mavenPwd, getFlutterPluginVersion(project))
}
// 改动:flutter插件依赖库版本号(以插件依赖库中pubspec.yaml#version为准)
String getFlutterPluginVersion(Project project) {
File pubspecFile = project.file("../pubspec.yaml")
String versionLine = pubspecFile.readLines().find { line ->
line.startsWith("version:")
}
return versionLine.split(":")[1].trim()
}
String getFlutterRoot(Project project) {
if (!project.hasProperty("flutter-root")) {
throw new GradleException("The `-Pflutter-root` flag must be specified.")
}
return project.property("flutter-root")
}
void addAarTask(Project project, String mavenUrl, variant) {
String variantName = variant.name.capitalize()
String taskName = "assembleAar$variantName"
project.tasks.create(name: taskName) {
// This check is required to be able to configure the archives before `publish` runs.
if (!project.gradle.startParameter.taskNames.contains(taskName)) {
return
}
// :flutter模块每次都执行"publish",保持和之前逻辑一致
def isFlutterProject = project.name == "flutter"
// :flutter模块依赖的插件校验下是否已上传maven仓库,不存在则执行"publish",避免每次提醒上传错误
if (isFlutterProject || !pluginInMavenRepo(project, mavenUrl, variant)) {
// Generate the Maven artifacts.
finalizedBy "publish"
}
}
}
// 是否本地仓库
static boolean isLocalMavenRepo(String mavenUrl) {
return mavenUrl.startsWith("file")
}
// 校验maven库中是否存在指定插件aar
boolean pluginInMavenRepo(Project project, String mavenUrl, variant) {
// 获取flutter插件版本号
def pluginVersion = ""
try {
pluginVersion = getFlutterPluginVersion(project)
} catch (Exception ignored) {
return false
}
def url = buildFileUri(project, mavenUrl, pluginVersion, variant.name.toLowerCase(), "aar")
if (isLocalMavenRepo(mavenUrl)) {
//本地仓库(判断文件是否存在)
return new File(url).exists()
} else {
//远程仓库(curl判断)
return curlResponseCode(url) == 200
}
}
// 构造指定后缀文件仓库地址,如http://nexus.corp.youdao.com/nexus/content/repositories/luna-android-release/com/example/my_flutter/flutter_release/1.0.2/flutter_release-1.0.2.pom
String buildFileUri(Project project, String mavenUrl, String version, String buildType, String suffix) {
// groupId使用默认,https://docs.gradle.org/current/userguide/publishing_maven.html#sec:identity_values_in_the_generated_pom
def groupId = project.group.toString().replace(".", "/")
// artifactId
def artifactId = "${project.name}_${buildType}"
def fileName = "$artifactId-${version}.${suffix}"
// 拼接仓库地址
if (!mavenUrl.endsWith("/")) {
mavenUrl += "/"
}
return "$mavenUrl$groupId/$artifactId/$version/$fileName"
}
// curl获取状态码
int curlResponseCode(String url) {
def stdout = new ByteArrayOutputStream()
exec {
// -I,只取headers
// -w %{http_code},状态码
commandLine 'curl', '-I', '-w %{http_code}', url
standardOutput = stdout
}
def response = stdout.toString().trim()
// 状态码最后3位
def length = response.length()
if (length >= 3) {
return response.substring(length - 3, length).toInteger()
}
return -1
}
// maven-publish has to be applied _before_ the project gets evaluated, but some of the code in
// `configureProject` requires the project to be evaluated. Apply the maven plugin to all projects, but
// only configure it if it matches the conditions in `projectsEvaluated`
allprojects {
apply plugin: "maven-publish"
}
projectsEvaluated {
// The module project is the `:flutter` subproject.
Project moduleProject = rootProject.subprojects.find { it.name == "flutter" }
assert moduleProject != null
assert moduleProject.hasProperty("maven-url")
// maven仓库
String mavenUrl = moduleProject.property("maven-url")
String mavenUser = moduleProject.property("maven-user")
String mavenPwd = moduleProject.property("maven-pwd")
String version = moduleProject.property("buildNumber")
configureProject(moduleProject, mavenUrl, mavenUser, mavenPwd, version)
// Gets the plugin subprojects.
Set<Project> modulePlugins = rootProject.subprojects.findAll {
it.name != "flutter" && it.name != "app"
}
// When a module is built as a Maven artifacts, plugins must also be built this way
// because the module POM's file will include a dependency on the plugin Maven artifact.
// This is due to the Android Gradle Plugin expecting all library subprojects to be published
// as Maven artifacts.
modulePlugins.each { pluginProject ->
configurePlugin(pluginProject, mavenUrl, mavenUser, mavenPwd)
moduleProject.android.libraryVariants.all { variant ->
// Configure the `assembleAar<variantName>` task for each plugin's projects and make
// the module's equivalent task depend on the plugin's task.
String variantName = variant.name.capitalize()
moduleProject.tasks.findByPath("assembleAar$variantName")
.dependsOn(pluginProject.tasks.findByPath("assembleAar$variantName"))
}
}
// 上传成功输出日志
gradle.buildFinished { buildResult ->
if (buildResult.failure == null) {
String groupId = moduleProject.group
String storageUrl = System.getenv('FLUTTER_STORAGE_BASE_URL') ?: "https://storage.googleapis.com"
String repoUrl = mavenUrl
if (mavenUrl.startsWith("file://")) {
repoUrl = mavenUrl.substring(7)
}
//pom文件地址
String pomUrl = buildFileUri(moduleProject, mavenUrl, version, "release", "pom")
println("""
上传maven仓库成功,通过下述方式引入flutter模块:
1. 打开<host>/app/build.gradle
2. 配置仓库地址:
repositories {
maven {
url '$repoUrl'
}
maven {
url '$storageUrl/download.flutter.io'
}
}
3. 添加flutter模块依赖:
dependencies {
implementation '${groupId}:flutter_release:${version}'
}
4. 查看*.pom文件(用于特殊情况时确认依赖是否正确):
${pomUrl}
""")
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment