使用 Gradle 插件优化 Flutter Android 插件开发中的 Flutter 依赖缺失问题

前言

在开发 Flutter 的 Android 插件时,你是否也遇到过这样的烦恼:在 Android Studio 中打开项目后,总是提示找不到 import io.flutter.xxx 包?虽然我们可以通过创建一个 resolve_flutter_depends.gradle 文件来解决这个问题,并在 build.gradle 中引用它,但这种方式比较笨拙,需要每个项目手动设置,非常不便。

实际上,我们可以利用 Gradle 插件来实现 Flutter 依赖的自动化配置,减少重复操作,提高开发效率。本文将介绍如何创建一个 Gradle 插件并发布到Maven仓库, 用于自动解决 Flutter Android 插件开发中的依赖问题。

创建 Gradle 插件

首先,我们来创建一个 Gradle 插件工程:

shell 复制代码
mkdir gradle_plugin_flutter_depends
cd gradle_plugin_flutter_depends
gradle init

gradle init 过程中,可以选择项目类型为 library。其它的看你自己的需要选择, 下图是我的选择:

插件项目

在项目的 build.gradle 文件中进行如下配置:

gradle 复制代码
plugins {
    id 'java-library'
    id 'java-gradle-plugin' // 添加 Gradle 组件
}

apply from: 'maven-push.gradle' // 插件发布配置,后面会讲到

repositories {
    mavenCentral()
    google()
}

dependencies {
    // Gradle 相关 API
    implementation gradleApi()
    implementation localGroovy()
}

gradlePlugin {
    plugins {
        create("FlutterGradle") { // 插件名称
            id = "pharos.flutter.dependencies" // 插件 ID
            implementationClass = "com.e.g.flutter_gradle.FlutterDependenciesPluginPlugin" // 插件实现类
        }
    }
}

实现 Flutter 依赖插件功能

接下来,我们编写插件的功能实现类:

java 复制代码
package com.e.g.flutter_gradle;

import org.gradle.api.Project;
import org.gradle.api.Plugin;
import org.gradle.api.artifacts.dsl.RepositoryHandler;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.nio.file.Paths;
import java.util.Properties;

public class FlutterDependenciesPluginPlugin implements Plugin<Project> {
    public void apply(Project project) {
        // 加载 local.properties 文件
        Properties localProperties = new Properties();
        File localPropertiesFile = project.getRootProject().file("local.properties");

        if (localPropertiesFile.exists()) {
            try (FileInputStream fis = new FileInputStream(localPropertiesFile)) {
                localProperties.load(fis);
            } catch (IOException e) {
                throw new RuntimeException("Failed to load local.properties file", e);
            }
        }

        // 获取 Flutter SDK 路径
        String flutterRootPath = localProperties.getProperty("flutter.sdk");
        if (flutterRootPath == null) {
            throw new IllegalStateException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.");
        }

        String[] storageUrl = {System.getenv("FLUTTER_STORAGE_BASE_URL")};
        if (storageUrl[0] == null) {
            storageUrl[0] = "https://storage.flutter-io.cn";
        }

        // 配置仓库
        RepositoryHandler repositories = project.getRepositories();
        repositories.google();
        repositories.mavenCentral();
        repositories.maven(repo -> repo.setUrl(storageUrl[0] + "/download.flutter.io"));

        // 获取引擎版本
        File engineVersionFile = Paths.get(flutterRootPath, "bin", "internal", "engine.version").toFile();
        String engineVersion;
        try {
            engineVersion = new String(java.nio.file.Files.readAllBytes(engineVersionFile.toPath())).trim();
        } catch (IOException e) {
            throw new RuntimeException("Failed to read engine version", e);
        }

        // 添加依赖
        project.afterEvaluate(evaluatedProject -> {
            if (evaluatedProject.getConfigurations().findByName("releaseImplementation") != null) {
                evaluatedProject.getDependencies().add("releaseImplementation", "io.flutter:flutter_embedding_release:1.0.0-" + engineVersion);
                evaluatedProject.getDependencies().add("releaseImplementation", "io.flutter:armeabi_v7a_release:1.0.0-" + engineVersion);
                evaluatedProject.getDependencies().add("releaseImplementation", "io.flutter:arm64_v8a_release:1.0.0-" + engineVersion);
            }

            if (evaluatedProject.getConfigurations().findByName("debugImplementation") != null) {
                evaluatedProject.getDependencies().add("debugImplementation", "io.flutter:flutter_embedding_profile:1.0.0-" + engineVersion);
                evaluatedProject.getDependencies().add("debugImplementation", "io.flutter:armeabi_v7a_profile:1.0.0-" + engineVersion);
                evaluatedProject.getDependencies().add("debugImplementation", "io.flutter:arm64_v8a_profile:1.0.0-" + engineVersion);
            }

            evaluatedProject.getDependencies().add("compileOnly", "io.flutter:flutter_embedding_debug:1.0.0-" + engineVersion);
            evaluatedProject.getDependencies().add("compileOnly", "io.flutter:armeabi_v7a_debug:1.0.0-" + engineVersion);
            evaluatedProject.getDependencies().add("compileOnly", "io.flutter:arm64_v8a_debug:1.0.0-" + engineVersion);
            evaluatedProject.getDependencies().add("compileOnly", "io.flutter:x86_debug:1.0.0-" + engineVersion);
            evaluatedProject.getDependencies().add("compileOnly", "io.flutter:x86_64_debug:1.0.0-" + engineVersion);
        });
    }
}

发布到 Maven 仓库

使用 maven-publish 插件发布插件到 Maven 仓库:

gradle 复制代码
# 必须添加此插件 才能发布 Maven
apply plugin: 'maven-publish'

def localProperties = new Properties()
def localPropertiesFile = rootProject.file('gradle.properties')
if (localPropertiesFile.exists()) {
    localPropertiesFile.withReader('UTF-8') { reader ->
        localProperties.load(reader)
    }
}

afterEvaluate {
    publishing {
        repositories {
            maven {
                name = 'fooRelease'
                allowInsecureProtocol = true
                url = localProperties.getProperty('mvn.url.release')
                credentials {
                    username = localProperties.getProperty('mvn.username')
                    password = localProperties.getProperty('mvn.password')
                }
            }
        }

        publications {
            release(MavenPublication) {
                groupId = localProperties.getProperty('mvn.groupid')
                artifactId = 'flutter-dependencies'
                version = "0.0.2"
                afterEvaluate { artifact(tasks.getByName("jar")) }
            }
        }
    }
}

执行以下命令发布插件:

shell 复制代码
./gradlew publishReleasePublicationToFooReleaseRepository

在项目中使用插件

在 Flutter 插件项目的 android/build.gradle 中引入发布的插件:

gradle 复制代码
buildscript {
    repositories {
        # 添加你的Maven仓库地址
        maven {
            url 'https://nexus.foo.com/repository/foo-moblie-central'
            content {
                includeGroup 'com.foo.flutter_gradle'
            }
        }
        google(){
         content {
            excludeGroup 'com.foo.flutter_gradle' 
         }
        }
        mavenCentral(){
         content {
            excludeGroup 'com.foo.flutter_gradle'
         }
        }
    }

    dependencies {
        # 添加你的插件依赖
        classpath 'com.foo.flutter_gradle:flutter-dependencies:0.0.1'
        classpath 'com.android.tools.build:gradle:7.3.0'
    }
}

# 你的插件
apply plugin: 'pharos.flutter.dependencies'

local.properties 文件中配置 Flutter SDK 路径:

properties 复制代码
sdk.dir=/Users/<USERNAME>/Library/Android/sdk
flutter.sdk=/Users/<USERNAME>/fvm/versions/custom_3.22.0-ohos

总结

通过创建 Gradle 插件,可以有效地简化 Flutter Android 插件开发中的 Flutter 依赖配置工作,避免了每次手动配置的繁琐操作,提高了开发效率和代码可维护性。希望本文能对你有所帮助,欢迎在开发中尝试这一方法。

撰写不易,请给个赞👍吧

相关推荐
dancing9991 小时前
Android Studio中Gradle 7.0上下项目配置及镜像修改
android·ide·android studio
EQ-雪梨蛋花汤3 小时前
【Part 2安卓原生360°VR播放器开发实战】第四节|安卓VR播放器性能优化与设备适配
android·性能优化·vr
每次的天空3 小时前
Android学习总结之kotlin篇(二)
android·学习·kotlin
刘洋浪子3 小时前
Android Studio中Gradle中Task列表显示不全解决方案
android·ide·android studio
橙子199110163 小时前
Kotlin 中 infix 关键字的原理和使用场景
android·开发语言·kotlin
后端码匠9 小时前
MySQL 8.0安装(压缩包方式)
android·mysql·adb
梓仁沐白11 小时前
Android清单文件
android
董可伦13 小时前
Dinky 安装部署并配置提交 Flink Yarn 任务
android·adb·flink
每次的天空14 小时前
Android学习总结之Glide自定义三级缓存(面试篇)
android·学习·glide
恋猫de小郭14 小时前
如何查看项目是否支持最新 Android 16K Page Size 一文汇总
android·开发语言·javascript·kotlin