Android Settings,SourceSet,自定义Plugin

简介: Android Settings,SourceSet,自定义Plugin

Settings 类


决定一个工程中有哪些模块是需要被处理的。


public interface Settings extends PluginAware, ExtensionAware {
  //默认的文件名称
    String DEFAULT_SETTINGS_FILE = "settings.gradle";
    //将指定的 project 加载到的构建中
    void include(String... projectPaths);
}


Settings 类如何被 gradle 初始化完全取决于 settings.gradle 文件的配置。setting.gradle 中就需要指定有哪些模块需要被处理。


include  ':app', ':core', ':detegateManager', ':tabHome', ':tabShop', ':tabDiscover', ':tabMall', ':tabMine', ':ui'


如上就是有多个模块被加载到构建中,Settings 会在 gradle 生命周期的初始化阶段执行,确定要构建的模块,并创建 project 对象


SourceSet 类


gradle 是如何从从 src/main/java/package/ 下面去读取我们的源码,然后生成字节码文件呢?其实就是通过 SourceSet 类的配置中拿到的。


SourceSet 类决定了我们所有的代码,资源,第三方库等存放的位置。


gradle 中约定大于配置,只要没有配置,那就是按约定的来。gradle 默认从 java 文件下获取源码,从 res 文件下获取资源 进行编译。这些约定可以进行修改。


通过 SourceSet 类我们可以修改默认的存放路径,如 so 的路径,res 的路径,java 文件的路径等。如下所示:


android {
    sourceSets {
            main {
                //修改 so 文件存放的位置
                jniLibs.srcDirs = ['libs']
            }
        }
}


使用上面的配置后,gradle 在加载 so 文件时就会从 libs 下进行加载。


修改资源路径:如果一个项目太过庞大,其代码还可以通过创建 package 来整理一下,看起来会更加简洁,容易寻找。但是资源文件却不行,默认只有一个 res 目录,所有的自愈都需要放在 res 中。但是通过 SourceSet 类可以指定多个 res 文件夹,这些文件夹里面就可以存放不同模块下的资源文件了。如下:


在 main 文件下新建文件夹 res-ad 用来存放广告资源,res-play 存放游戏资源。创建完成后在 build.gradle 中的 android 下添加如下代码:


sourceSets {
        main {
            res.srcDirs = ['src/main/res',
                           'src/main/res-ad',
                           'src/main/res-play']
        }
}


接着同步一下,就会发现这两个文件夹上面的图标和 res 的图标是一样的了。


0a2653c851af460fa595bd959398a8f1.png


Plugin 详解及自定义 Plugin


Gradle 插件使用 Groovy 开发的,而 Groovy 完全兼容 Java ,使用 AS 完全可以开发 Gradle 插件。


处理插件:Gradle 会自动找到插件的所在位置,如 buildSrc 名字会被 Gradle 识别为 插件工程


应用环境:一旦插件被应用到构建的脚本中,那么插件对应的 apply 方法就会被调用


插件项目的创建:在 as 中新建一个 library。删除一些内容。使其和图片中的一样:


0a2653c851af460fa595bd959398a8f1.png


  groovy 下新建一个包名。


META-INF/gradle-plugins/下新建一个 .properties 文件,这里的为文件名字最终会出现在:


apply plugin: 'com.car.srcplugin'


注意 :build.gradle 中所有的内容都需要删掉


下面开始一个小 Demo:还是保存每次发布的版本信息。只不过有了很大的改进。


1,配置一些 build.gradle


apply plugin: 'groovy'
sourceSets {
    main {
        groovy {
            srcDir 'src/main/groovy'
        }
        resources {
            srcDir 'src/main/resources'
        }
    }
}
dependencies {
    //gradle sdk
    implementation gradleApi()
    //groovy sdk
    implementation localGroovy()
}


2,自定义 Taks


class UpDataInfoTask extends DefaultTask {
    private VersionInfo versionInfo
    ReleaseInfoTask() {
        //设置组名和描述信息
        group = '345'
        description = 'update the release info'
    }
    /**
     * 使用 TaskAction 注解,这个方法会执行在执行阶段
     * doFirst 就是给这个方法的最前面添加代码
     * doLast 就是给这个方法的最后面添加代码
     */
    @TaskAction
    void doAction() {
        upDataInfo()
    }
    /**
     * 将 Extension 类中的信息写入到指定的文件中
     */
    void upDataInfo() {
        project.logger.error "------------------- 开始插入信息 -------------------"
        String versionNameMsg = project.extensions
                .upDataInfo.versionName
        String versionCodeMsg = project.extensions
                .upDataInfo.versionCode
        String versionInfoMsg = project.extensions
                .upDataInfo.versionInfo
        String buildType = project.extensions.
                upDataInfo.buildType
        if (buildType == null || buildType.isEmpty()) {
            buildType = "Release"
        }
        File file = project.file(buildType + ".json")
        if (file != null && !file.exists()) {
            file.createNewFile()
        }
        if (file.text != null && file.text.size() >= 0) {
            String text = file.text
            if (text != null && !text.isEmpty()) {
                versionInfo = new JsonSlurper().parseText(text)
            } else {
                versionInfo = new VersionInfo()
                versionInfo.setUpDataInfo = []
            }
            if (versionInfo.setUpDataInfo.size() > 0) {
                //如果版本号一样,使用新的
                int pos = versionInfo.setUpDataInfo.size() - 1;
                if (versionNameMsg == versionInfo.setUpDataInfo.get(pos).versionName) {
                    project.logger.error "------------------- 版本号相同,已替换 -------------------"
                    versionInfo.setUpDataInfo.remove(pos)
                }
            }
            VersionInfo.UpDataInfoBean bean = new VersionInfo.UpDataInfoBean();
            bean.versionCode = versionCodeMsg
            bean.versionName = versionNameMsg
            bean.versionInfo = versionInfoMsg
            bean.versionTime = stampToDate(System.currentTimeMillis())
            versionInfo.setUpDataInfo.add(bean)
            String json = JsonOutput.toJson(versionInfo)
            file.withWriter {
                write ->
                    write.write(JsonOutput.prettyPrint(json))
            }
            project.logger.error "------------------- 更新信息已生成 -------------------"
        }
    }
    private static String stampToDate(long time) {
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        Date date = new Date(time)
        simpleDateFormat.format(date)
    }
}


3,VersionInfo


class VersionInfo {
    private List<UpDataInfoBean> updataInfo;
    public List<UpDataInfoBean> getSetUpDataInfo() {
        return updataInfo;
    }
    public void setSetUpDataInfo(List<UpDataInfoBean> relaseInfo) {
        this.updataInfo = relaseInfo;
    }
    public static class UpDataInfoBean {
        /**
         * versionName :
         * versionCode :
         * versionInfo :
         * versionTime :
         */
        private String versionName;
        private String versionCode;
        private String versionInfo;
        private String versionTime;
        public String getVersionName() {
            return versionName;
        }
        public void setVersionName(String versionName) {
            this.versionName = versionName;
        }
        public String getVersionCode() {
            return versionCode;
        }
        public void setVersionCode(String versionCode) {
            this.versionCode = versionCode;
        }
        public String getVersionInfo() {
            return versionInfo;
        }
        public void setVersionInfo(String versionInfo) {
            this.versionInfo = versionInfo;
        }
        public String getVersionTime() {
            return versionTime;
        }
        public void setVersionTime(String versionTime) {
            this.versionTime = versionTime;
        }
    }
}


4,UpDataInfoExtension


闭包中要用到的属性


class UpDataInfoExtension {
    /**
     * code
     */
    String versionCode
    /**
     * name
     */
    String versionName
    /**
     * 发布信息
     */
    String versionInfo
    /**
     * 打包类型。默认为 Release ,也可以是 Debug。注意 首字母大写。
     */
    String buildType
}


5,自定义 plugin


/**
 * 自定义插件
 */
class GradleStudyPlugin implements Plugin<Project> {
    Project mProject = null;
    /**
     * 插件被引入时要执行的方法
     * @param project 引入当前插件的 project
     */
    @Override
    void apply(Project project) {
        mProject = project
        def android = mProject.extensions.android
        //通过在外边定义 upDataInfo 闭包,完成对 UpDataInfoExtension 的初始化
        project.extensions.create('upDataInfo', UpDataInfoExtension)
        //创建 Task
        UpDataInfoTask task = project.tasks.create('upDataInfoTask', UpDataInfoTask)
        //配置阶段完成后执行
        mProject.afterEvaluate {
            String buildType = mProject.extensions.upDataInfo.buildType
            //默认 Release
            if (buildType == null || buildType.isEmpty()) {
                buildType = "Release"
            }
            mProject.logger.error("------------------- ${buildType} -------------------")
            def buildTask = mProject.tasks.getByName("assemble${buildType}")
            if (buildTask == null) {
                throw GradleException('the build task is not fond')
            }
            buildTask.doLast {
                task.upDataInfo()
            }
        }
    }
}


6,META-INF/gradle-plugins/


META-INF/gradle-plugins/下新建一个 .properties 文件。文件名字一般和包名一样


implementation-class=com.car.srcplugin.GradleStudyPlugin


这里指向自定义的 Plugin


7,使用方式


每次打Release 或者 Debug 包的时候这个会自动执行。或者是使用命令行直接启动也可以。


在 app/build.gradle 中引入


apply plugin: 'com.car.srcplugin'


创建闭包,注意和 android 闭包平级


upDataInfo {
    versionCode String.valueOf(version_code)
    versionName version_name
    versionInfo version_info
    //默认 Release,还可以是Debug ,注意首字母大写
    buildType "Debug"
}


8,使用结果


0a2653c851af460fa595bd959398a8f1.png2d65d23f6d4748949b924e4057485923.png


9,总结


这个插件也写了好久,因为也是刚开始学,到现在有些问题还没有解决。以后再慢慢解决吧。


android 插件对 gradle 扩展


在 build.gradle 中,有一个 android 的闭包,在这个闭包中可以的定义非常多的内容。BaseExtension 类就是 闭包中能够调用的所有方法如下:


public abstract class BaseExtension implements AndroidConfig {
    /** Secondary dependencies for the custom transform. */
    private final List<List<Object>> transformDependencies = Lists.newArrayList();
    protected final GlobalScope globalScope;
    private final DefaultConfig defaultConfig;
    private final AaptOptions aaptOptions;
    private final LintOptions lintOptions;
    private final ExternalNativeBuild externalNativeBuild;
    private final DexOptions dexOptions;
    private final TestOptions testOptions;
    private final CompileOptions compileOptions;
    private final PackagingOptions packagingOptions;
    private final JacocoOptions jacoco;
    private final Splits splits;
    ......
}


上面列举了部分的属性。android 闭包中所有的属性方法都是调用这个类里面的。


相关文章
|
1月前
|
缓存 前端开发 Android开发
安卓开发中的自定义视图:从零到英雄
【10月更文挑战第42天】 在安卓的世界里,自定义视图是一块画布,让开发者能够绘制出独一无二的界面体验。本文将带你走进自定义视图的大门,通过深入浅出的方式,让你从零基础到能够独立设计并实现复杂的自定义组件。我们将探索自定义视图的核心概念、实现步骤,以及如何优化你的视图以提高性能和兼容性。准备好了吗?让我们开始这段创造性的旅程吧!
27 1
|
2月前
|
Android开发 开发者
安卓应用开发中的自定义视图
【9月更文挑战第37天】在安卓开发的海洋中,自定义视图犹如一座座小岛,等待着勇敢的探索者去发现其独特之处。本文将带领你踏上这段旅程,从浅滩走向深海,逐步揭开自定义视图的神秘面纱。
44 3
|
4月前
|
存储 Shell Android开发
基于Android P,自定义Android开机动画的方法
本文详细介绍了基于Android P系统自定义开机动画的步骤,包括动画文件结构、脚本编写、ZIP打包方法以及如何将自定义动画集成到AOSP源码中。
93 2
基于Android P,自定义Android开机动画的方法
|
2月前
|
数据可视化 Android开发 开发者
安卓应用开发中的自定义View组件
【10月更文挑战第5天】在安卓应用开发中,自定义View组件是提升用户交互体验的利器。本篇将深入探讨如何从零开始创建自定义View,包括设计理念、实现步骤以及性能优化技巧,帮助开发者打造流畅且富有创意的用户界面。
106 0
|
4月前
|
供应链 物联网 区块链
未来触手可及:探索新兴技术的趋势与应用安卓开发中的自定义视图:从基础到进阶
【8月更文挑战第30天】随着科技的飞速发展,新兴技术如区块链、物联网和虚拟现实正在重塑我们的世界。本文将深入探讨这些技术的发展趋势和应用场景,带你领略未来的可能性。
|
4月前
|
测试技术 Android开发 Python
探索软件测试的艺术:从基础到高级安卓应用开发中的自定义视图
【8月更文挑战第29天】在软件开发的世界中,测试是不可或缺的一环。它如同艺术一般,需要精细的技巧和深厚的知识。本文旨在通过浅显易懂的语言,引领读者从软件测试的基础出发,逐步深入到更复杂的测试策略和工具的使用,最终达到能够独立进行高效测试的水平。我们将一起探索如何通过不同的测试方法来确保软件的质量和性能,就像艺术家通过不同的色彩和笔触来完成一幅画作一样。
|
1月前
|
搜索推荐 前端开发 Android开发
安卓应用开发中的自定义视图实现
【10月更文挑战第30天】在安卓开发的海洋中,自定义视图是那抹不可或缺的亮色,它为应用界面的个性化和交互体验的提升提供了无限可能。本文将深入探讨如何在安卓平台创建自定义视图,并展示如何通过代码实现这一过程。我们将从基础出发,逐步引导你理解自定义视图的核心概念,然后通过一个实际的代码示例,详细讲解如何将理论应用于实践,最终实现一个美观且具有良好用户体验的自定义控件。无论你是想提高自己的开发技能,还是仅仅出于对安卓开发的兴趣,这篇文章都将为你提供价值。
|
1月前
|
Android开发 开发者 UED
安卓开发中自定义View的实现与性能优化
【10月更文挑战第28天】在安卓开发领域,自定义View是提升应用界面独特性和用户体验的重要手段。本文将深入探讨如何高效地创建和管理自定义View,以及如何通过代码和性能调优来确保流畅的交互体验。我们将一起学习自定义View的生命周期、绘图基础和事件处理,进而探索内存和布局优化技巧,最终实现既美观又高效的安卓界面。
41 5
|
2月前
|
XML 前端开发 Java
安卓应用开发中的自定义View组件
【10月更文挑战第5天】自定义View是安卓应用开发的一块基石,它为开发者提供了无限的可能。通过掌握其原理和实现方法,可以创造出既美观又实用的用户界面。本文将引导你了解自定义View的创建过程,包括绘制技巧、事件处理以及性能优化等关键步骤。
|
3月前
|
Android开发 开发者
安卓开发中的自定义视图:从入门到精通
【9月更文挑战第19天】在安卓开发的广阔天地中,自定义视图是一块充满魔力的土地。它不仅仅是代码的堆砌,更是艺术与科技的完美结合。通过掌握自定义视图,开发者能够打破常规,创造出独一无二的用户界面。本文将带你走进自定义视图的世界,从基础概念到实战应用,一步步展示如何用代码绘出心中的蓝图。无论你是初学者还是有经验的开发者,这篇文章都将为你打开一扇通往创意和效率的大门。让我们一起探索自定义视图的秘密,将你的应用打造成一件艺术品吧!
72 10