Android自定义Gradle插件的详细过程

一、Gradle

我们知道在我们现在使用Android Stduio开发Android项目的时候,Android Studio是基于Gradle来帮助我们构建,管理项目的。
Gradle:Gradle是一个项目构建工具,用来帮助我们管理项目的依赖、打包、发布、部署等工作。
Gradle是通过如build.gradle这种gradle脚本来进行项目构建的,所以我们对项目的构建配置都是可以写在gradle构建脚本中。
gradle构建脚本使用的是Groovy语言,Groovy语言也是一种jvm语言,最终也是编译成class文件然后在jvm上执行,所以所有的Java语言的特性Groovy都支持,我们可以完全混写Java和Groovy;

Gradle插件:

Gradle是一个构建项目的工具,但是Gradle本身只提供了一个核心框架,各种构建功能,比如编译、依赖、打包等都是通过插件来完成的;
比如我们使用构建Android项目,就需要可以构建Android的gradle插件,所以我们在Android Studio中新建的每一个项目中都会在Project的build.gradle中都会引入构建Android项目的插件

dependencies {
        classpath "com.android.tools.build:gradle:4.1.3"
     }

这个Gradle插件是Google开发的gradle插件,插件中实际上是定义了一系列的Task,这些Task的执行对应的就是一系列的构建操作,如build(编译)、install(安装)等,而构建Android项目的gradle插件就定义了如build、install等Task;

除了使用Google以及其他开发好的一些插件,我们自己也可以开发Gradle插件,来帮助我们自动完成一些任务,比如多渠道打包插件,比如每次发布APK之前,可能还需要对APK进行加固,所以也可以开发一个加固插件;这样,引入插件之后,在Gradle窗口中,直接点击对应的Task,就会自动加固了,非常方便;
自定义插件也是使用Groovy语言来进行开发;

二、Groovy语法

上面我们说过Groovy是一种JVM语言,可以完全使用Java语法编写代码,但是Groovy也是 有自己的语法的,我们现在来学习一下Groovy的基本语法;

(1)Groovy中变量和方法的声明

Groovy中通过def关键字来声明变量和方法

  def a=1;

     def b="hello world";

     def int c=1;

     def test(){ //定义方法

         println("123");

         return 0;

     }

Groovy写法相对来说比较随意,很多东西都是可以省略的;
语句结尾的分号可以省略;
定义变量和方法时,变量的类型,和方法的返回值也可以省略;
Groovy中类型是弱化的,类型是可以动态推断的;
Groovy中很多东西都是可以省略的:
方法调用时,括号也是可以省略的
方法的返回值,return都是可以省略的

def a=1;

    a="Hello World"   

    def test(a){

       println(a);

       1; //方法的返回值为1,返回值可以省略return 

    }

    test 1  //调用方法,可以省略括号

(2) Groovy中的数据类型

基本数据类型

Java中的基本数据类型,Groovy中都是有的;
但是不同的是,Groovy中的基本数据类型都是以对象的类型存在的;

 def int a=1;

    def double b=1.1;

    println(a.class);

    println(b.class);

对象类型
和Java中的对象类型是一样的
这里把String类型单独拿出来说下,因为Groovy中字符串的拼接比较有特色的,可以在字符串中使用 ${变量},来拼接变量的值

def a=1;

    String b="Hello ${a}" //字符串结果为 Hello 1

(3) 闭包Closure

Groovy中的闭包是一个开放的、匿名的代码块,可以接受参数,返回值并分配给变量

{ [closureParameters] -> statements }

//定义闭包

     def closure = { println("Hello World") }

     def closure1= { a,b -> a+b  }

     //调用闭包

     closure();

     closure.call(); //函数式调用或者使用call方式调用,这两种方式调用闭包都是可以的

     def a=closure1(1,2);

     def a=closure1.call(1,2);

(4) Grovvy中的数据结构

前面我们说过Java中的东西,Grovvy中都是可以使用,所以Java中的数据结构,Grovvy中当然都是可以使用的;
这里主要学习下Grovvy中和Java中不同的常用语法:

List集合

//先写一个Java中的语法

    List list=new ArrayList<>();

    list.add(1);

    list.add(2);

    //Groovy除了像Java中一样写法,还可以这样来定义List

    def lists=[1,2,3];

    lists.add(4);

    lists.add(5);

    print(lists.class); //我们打印这个lists的class,它就是java.util.ArrayList

当然既然它就是Java中的ArrayList,当然还有remove,get等等API,这里就不一一列出来了,但是Groovy中List还提供了find查找的API,这个是Java中所没有的

 def result=lists.find{

      return it%2==0;

    } //这里find查找方法传入的参数是一个闭包,返回的是第一个能整除2的元素

 def results=lists.findAll {

      return it%2==0;

    } //查找List中所有的能整除2的元素 

 def resList=lists.sort {

        x1,x2->  return x1==x2?0:x1>x2?1:-1

    } //List中sort方法,传入一个闭包参数,用于对List排序

lists.each{

       print(it+",");

    } //each方法遍历List

List还有一些其他方法,这里可不一一列举了

Map

 //先写一个Java中Map的写法

     Map map=new HashMap<>();

     map.put("a",1);

     map.put("b",2);

     //Groovy除了像Java中一样写法,还可以这样来定义Map

     def map=["a":1,"b":2];

     prinlt(map.get("a")); //获取某个键对应的值

     prinltn(map.a);//map.key 这种方式也可以获取map中某个键的值

     println(map.getClass()); //这样定义map,Map的默认数据类型是java.util.LinkedHashMap

                              //这里我们是使用map.getClass()来获取map的类,而不能map.class来获取

                              //是因为map有map.key这种用法,用来获取map中键为key的值,所以如果写map.class

                              //会被认为是获取map中键为class的值,所以这里只能用map.getClass()来获取map的class类型

    def v=map.find {

     if (it.getValue()==2){
          return it;
      }

   } //map中的find方法,传入一个闭包参数,可以查找map中第一个满足条件的一个Entry(键值对实体)

   println(v.key);

   map.each {

     println(it.getKey()+":"+it.getValue());

   } //可以使用map的each方法,参数是一个闭包,来遍历map

   map还有一些其他方法,所以这里可不一一列举了

   def resMap=map.sort {

      e1,e2->

        return e1.key==e2.key?0:e1.key>e2.key?1:-1

  } //map的sort方法传入一个闭包参数,对map进行排序,返回的是一个排序后的新的map,注意原map并没有变化

Range (范围)
rang相当于一个轻量级的List

def rang=1..10 //这里相当于定义了一个集合,集合中的元素值从1到10

   println(range.class); //groovy.lang.IntRange

   println(rang[0]) //range[0]为1 

   println(range.getFrom());// 1 range.getFrom() 获取range的下限值

   println(range.getTo()); //10 range.getTo()获取range的上限值

   //如果定义的def range=10..1; range.getFrom()和range.getTo()的值还是1,10

   //因为10..1 下限值还是1,上限值还是10  

   def charRange='f'..'a';

   charRange.each {

     println(it)

   } //打印出 f,e,d,c,b,a

   def score=60;

   switch (score){
    case 0..59:
        println("及格");
        break
    case 60..85:
        println("及格");
        break
    case 86..100:
        println("优秀");
        break
}

(5)Groovy中的class(类)、inteface(接口)、trait

class

Groovy中的class(类)和Java中的class(类)是一样的,唯一的区别在于
默认的类、成员、方法的访问权限都是public的

interface

Groovy中的interface(接口)和Java中的interface(接口)是一样的,区别可能还是Groovy中定义接口的时候,如果不写访问权限默认就是public的而Java中定义接口的时候,如果不写访问权限,默认不是public的,那么不同包下的类是无法访问这个接口的;

trait

trait这个是Groovy中新加的类型,但是其实他就是一种介于抽象类和接口之间的类型;trait中可以定义抽象方法(即不实现),也可以定义正常方法; 使用的时候,和接口一样,也是要implement的,非抽象类实现是需要实现其抽象方法

trait MyTrait{

      abstract void test();

      void play(){

         prinlt("play game");

      }

    }  

    class TestClass implement MyTrait{

       @Override
       void test(){

       }

    }

三、自定义Gradle插件

自定义插件的方式:

1.独立项目

一个独立的Java项目/模块,可以将文件包发布到仓库(jcenter),使其他项目方便引用

2.Build script脚本

把插件写在build.gradle文件中,一般用于简单的逻辑,只在该build.gradle中可见

3.buildSrc目录

将插件源码放在buildSrc/src/main/groovy/中,只对该项目可见

我们这里以独立的Java Library模块自定义插件方式为例,来学习一下如何自定义一个Gradle插件;

每次发布APK之前,可能还需要对APK进行加固,所以也可以开发一个加固插件,来自动进行APK加固,我们这里以开发一个360加固插件为例;

我们知道如果是手动使用360加固,我们肯定是需要打开360加固的软件,然后输入用户名,密码登录进软件,然后选择应用加固选项,上传打包好的APK文件,就会自动进行加固,加固好之后,就会自定下载加固好的APK,然后我们还需要对加固好的APK文件进行签名,签名后的加固APK文件就可以正常安装使用了;


如果我们是使用自定义插件的方式来自动完成360加固,那上面这些步骤,从登录开始到上传应用,到加固,到对加固后的应用进行签名,都要以代码的方式来实现;

(1)我们使用Android Studio来创建一个正常的Android项目,在Android项目中新建一个Java Library Module;

Java Library Module名字,这里我们取plugin

Module的build.gradle文件中引入groovy插件,dependencies中

引入gradle插件,以及gradleApi因为在编写插件的时候,是要用到gradle相关的API的

plugins {  id 'groovy'  }   或者 apply plugin:'groovy'

dependencies {

    implementation 'com.android.tools.build:gradle:4.1.3'
    implementation gradleApi()

  }

(2) Android Studio 切换项目试图为Project,然后修改plugin的src/main/java 这个java目录名字为groovy

(3) 然后在src/main/groovy/…(包名)/下新建插件源码文件

这里要新建File(注意这里必须要新建一个File,不是新建java ,class等),File文件的名字以.groovy后缀结尾

我们这里新建一个GiaGuTask.groovy 的File,然后在GiaGuTask.groovy中开始插件的开发:首先要先添加包名,由于 Android Stuido不能识别.groovy文件 所以不会给我们自动添加包名,所以需要我们自己添加包名;package com.example.plugin

这个Task中就是将上述的登录360加固软件,上传APK,加固,签名加固后的APK文件,全部用执行命令的方式来实现,360加固软件包下的help.txt中实际上就提供了上 登录360加固软件,上传APK,加固,签名加固后的APK文件的命令行命令

所以我们的新建的Task如下:

package com.example.plugin

import com.android.builder.model.SigningConfig
import org.gradle.api.DefaultTask
import org.gradle.api.tasks.TaskAction

class GiaGuTask extends DefaultTask{

    GiaGuBean mGiaGuBean;

    SigningConfig signingConfig;

    File apkFile;

    GiaGuTask() {
        group="jiagu"
    }

    @TaskAction
    void run() {

        project.exec {

            it.commandLine(
                    "java",
                    "-jar",
                    mGiaGuBean.getJiaGuTools(),
                    "-login",
                    mGiaGuBean.getUserName(),
                    mGiaGuBean.getPassword(),

            );

        }

        if (signingConfig) {

            project.exec {

                it.commandLine(
                        "java",
                        "-jar",
                        mGiaGuBean.getJiaGuTools(),
                        "-importsign",
                        signingConfig.storeFile.absolutePath,
                        signingConfig.storePassword,
                        signingConfig.keyAlias,
                        signingConfig.keyPassword
                )

            }
        }

        project.exec {

            it.commandLine("java",

                    "-jar",

                    mGiaGuBean.getJiaGuTools(),

                    "-jiagu",

                    apkFile.absolutePath,

                    apkFile.parent,

                    "-autosign"

            )

        }

    }

}

当然这里的GiaGuTask使用到了一个GiaGuBean,这个GiaGuBean里面定义了一些我们需要到时候在build.gradle
设置的配置信息,登录的用户名,密码,加固工具所在的位置(加固工具就是360加固软件包下的jiagu.jar文件)

这些需要从build.gradle中设置的配置信息,我们需要在GiaGuBean这个实体类中定义,并且定义set,get方法

package com.example.plugin

class GiaGuBean {

    String userName;
    String password;
    String jiaGuTools

    String getUserName() {
        return userName
    }

    void setUserName(String userName) {
        this.userName = userName
    }

    String getPassword() {
        return password
    }

    void setPassword(String password) {
        this.password = password
    }

    String getJiaGuTools() {
        return jiaGuTools
    }

    void setJiaGuTools(String jiaGuTools) {
        this.jiaGuTools = jiaGuTools
    }

}

然后新建一个GiaGuPlugin.groovy 的File,然后定义一个class GiaGuPlugin 需要实现 DefaultPlugin
并且实现apply方法,在apply方法中进行相应的实现,并且创建一个或者多个Task的,因为最终的插件功能,都是一个个Task的执行

package com.example.plugin

import com.android.build.gradle.AppExtension
import com.android.build.gradle.api.ApplicationVariant
import com.android.build.gradle.api.BaseVariantOutput
import com.android.builder.model.SigningConfig
import org.gradle.api.Plugin
import org.gradle.api.Project

class GiaGuPlugin implements Plugin<Project>{

    @Override
    void apply(Project project) {
        GiaGuBean giaGuBean = project.extensions.create("jiagu", GiaGuBean.class);

        project.afterEvaluate {

            AppExtension appExtension = project.extensions.android;

            appExtension.applicationVariants.all {
                    //debug/release

                ApplicationVariant variant ->

                    //对应变体(debug/release)的签名配置
                    SigningConfig signingConfig = variant.signingConfig;

                    variant.outputs.all {

                        BaseVariantOutput baseVariantOutput ->

                            //输出的APK文件
                            File apkFile = baseVariantOutput.outputFile;

                            //创建加固任务
                            GiaGuTask giaGuTask = project.tasks.create("jiagu${variant.baseName.capitalize()}", GiaGuTask.class);
                            giaGuTask.mGiaGuBean = giaGuBean;
                            giaGuTask.signingConfig = signingConfig;
                            giaGuTask.apkFile =apkFile;

                    }
            }

        }

(4)插件的配置

插件开发好了之后,就需要进行配置,plugin Module的src/main目录下新建一个resources目录,再在resources目录下新建一个META-INF目录,再在META-INF目录下新建一个gradle-plugins目录; 然后在gradle-plugins目录下新建一个以 .properties后缀的文件,这个文件的名字就是到时候我们在引用插件时的名字我们这里取名:com.example.plugin.properties;这个文件里面我们需要配置插件的实现类

  implementation-class=com.example.plugin.GiaGuPlugin

到时候我们引用插件的时候就使用com.example.plugin这个名字;

(5)打包插件上传仓库

我们这里是打包插件上传Maven本地仓库,需要依赖maven-plugin插件,所以在plugin这个Java Library Module的build.gradle中添加maven-plugin插件的使用

apply plugin:'maven-publish'

publishing{

            publications{

            Jiagu(MavenPublication){ //Jiagu 这个名字随意取

            from components.java  //这个表示要把源码生成的jar包上传

            groupId 'com.example' //配置插件的groupId(分组ID)

            artifactId "plugin"   //配置ID

            version "1.0" //配置版本号
        }

     }

   } 

groupId、artifactId、version这三个配置构成了到时候我们依赖插件的时候的写法: groupId:artifactId:version,我
们到时候依赖这个plugin插件的时候,应该是在Android项目的Project的build.gradle的dependencies中添加依赖:classpath “com.example:plugin:1.0”
引用maven-publish插件之后,build(编译) plugin module之后,我们就可以在gradle窗口中查看到plugin下Tasks下会有publishing的Task,点开publishing这个Task下,我们点击publishToMavenLocal(打包上传插件到本地的maven库),操作成功过后,在C:\Users\Administrator\下回有一个.m2目录,这个目录的repository目录下会有 com\example\plugin这个目录所以是1.0(version)目录下就会有对应的插件plugin-1.0.jar,和两个插件信息文件:plugin-1.0.module、plugin-1.0.pom;


(5)使用插件

添加插件的依赖
我们在Android项目中的Project的build.gradle中添加插件依赖 由于我们使用的是本地maven库中的插件,所以repositories中需要添加mavenLocal()仓库

repositories {

           ...

           mavenLocal()

         }                         

      dependencies {
        ...
        classpath "com.example:plugin:1.0" 

        //就是之前上传的是偶配置groupId:artifactId:version

      } 

引用插件

在Android项目主module(一般为app)的build.gradle中引用插件

apply plugins:'com.example.plugin' //就是开发插件的时候resources/META-INF/gradle-plugins/com.example.plugin.properties 这个文件的名字

或者现在都是这种写法,在plugins{}下添加插件ID

plugins {

      ...

      id 'com.example.plugin' 

      //就是开发插件的时候resources/META-INF/gradle-plugins/com.example.plugin.properties 这个文件的名字 

}

当然app主module中的build.gradle中还要配置之前在定义GiaGuBean中的登录用户名,密码,加固工具位置信息

执行插件任务

上述步骤之后,就会在gradle窗口中主module(app)的Tasks下会有一个jiagu任务,这个名字实际就是你开发插件的 时候,定义Task时候,为Task设置的groupId,如果没有设置task的groupId,则插件的任务会在module(app)Tasks的other目录下点击jiagu下的操作,就会执行我们的加固任务;
当然我们要先确保APK文件已经存在,因为之前我们定义GiaGuPlugin.groovy时,里面APK文件使用的是baseVariantOutput.outputFile,也即build/outputs/apk/下release或者debug目录下的APK,所以我们只要build一下就会生成APK文件,然后我们再点击gradle窗口下,app/Tasks/jiagu下的加固任务即可进行加固

整个加固的过程,在run窗口下都会有日志打印


加固任务执行完毕之后build/outputs/apk/ 对用的目录下就会生成加固签名后的APK文件

以上就是一个自定义gradle插件的,实现、上传、使用过程

到此这篇关于Android自定义Gradle插件的文章就介绍到这了,更多相关Android自定义Gradle插件内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • 为Android Studio编写自定义Gradle插件的教程

    Google已经建议Android开发全部转向Android Studio开发,Android Studio 是使用gradle编译.打包的,那么问题来了,gradle可是有一堆东西...,为了彻底了解gradle,今天就来学习下如何写自己的gradle插件(当然插件源码是使用groovy写的),先看如下代码目录: 如上图所示,plugin目录是插件源码目录,sample是用来测试插件的. 1.在目录plugin/src/main/groovy/com/micky/gradle/下新建插件类My

  • 解决Android studio3.6安装后gradle Download失败(构建不成功)

    因为课程需要,昨天好多同学在安装Android studio3.6.1后,无法构建,不知道什么原因,我的电脑上使用的是之前3.4版本的,可以正常使用,所以没太关心.但晚上我想到3.6版本应该有一些新功能,所以我就想升级一下,升级完之后,发现之内的设计视图是不显示的,需要该工程成功构建之后才能正常使用,于是我就build一下,结果就凉凉了 gradle Download十几分钟,然后失败 两次之后我想到可能是因为跨版本更新可能导致很多东西报错.于是卸载重新安装新版本的,之后构建情况一模一样, gr

  • 关于Android中Gradle和jar包下载慢的问题及解决方法

    gradle下载慢问题 解决方法 下载之后自行安装 ps:就是手动更新. 官网地址和gradle各版本下载地址: 官网:http://gradle.org/release-candidate/ 各版本下载地址:http://services.gradle.org/distributions 步骤一: 通过下载地址,然后用自己的下载工具(IDM.迅雷等)进行下载. 一般来说官网的稍微慢一点,看个人情况来定. 步骤二: 把下载的Gradle解压 步骤三: Android studio中选择Gradl

  • Android 自定义gradle property详解及实例代码

    Android 自定义gradle property 在Android studio上运行项目,gradle的配置是必不可少的,但是随着项目的逐渐成长,迎面而来的就是.各种依赖包的添加,数不胜数的签名,渠道包等,整个gradle变得很乱,这样其实我们可以将gradle的部分内容分离出来放在另一个自定义gradle内. 如这时我们添加的Plugin 就只要对其赋值就可以了. 步骤: 在总项目根目录下创建 dependencies.gradle文件(名字可以自定义) 根目录下创建的自定义内容如下:

  • Android Studio Gradle 更换阿里云镜像的方法

    使用 Android Studio 开发时经常遇到编译卡住的问题,原因是 Gradle 下载依赖资源过慢.没办法,有长城在,还是得换镜像. 同样,这是个普遍存在的问题,我们希望可以对它进行全局配置.在 .gradle (路径参考 C:\Users\username\.gradle )目录下新增 init.gradle 文件,内容如下: allprojects{ repositories { def ALIYUN_REPOSITORY_URL = 'http://maven.aliyun.com/

  • 解决Android Studio Gradle Metadata特别慢的问题

    如下所示: 更改build.gradle buildscript { repositories { // jcenter() // jcenter(){ url 'http://jcenter.bintray.com/'} maven{url 'http://maven.aliyun.com/nexus/content/groups/public/'} maven { url "https://jitpack.io" } google() } dependencies { classp

  • Android Gradle依赖管理、去除重复依赖、忽略的方式

    常用依赖 //1.直接依赖第三方开源库,一般是托管在 jitpack 或者 jcenter implementation 'com.google.code.gson:gson:2.2.4' implementation 'com.android.support:cardview-v7:25.0.0' implementation 'com.android.support:design:25.0.0' //2.直接依赖本地的aar文件,一般是在libs目录下 implementation(name

  • Android自定义Gradle插件的详细过程

    一.Gradle 我们知道在我们现在使用Android Stduio开发Android项目的时候,Android Studio是基于Gradle来帮助我们构建,管理项目的. Gradle:Gradle是一个项目构建工具,用来帮助我们管理项目的依赖.打包.发布.部署等工作. Gradle是通过如build.gradle这种gradle脚本来进行项目构建的,所以我们对项目的构建配置都是可以写在gradle构建脚本中. gradle构建脚本使用的是Groovy语言,Groovy语言也是一种jvm语言,

  • Android自定义时间轴的实现过程

    本文讲述Android自定义时间轴的实现过程,供大家参考,具体内容如下 相关视频链接: Android自定义控件系列 http://edu.csdn.net/course/detail/3719/65396 Android视频全系列 http://edu.csdn.net/course/detail/2741/43163 时间轴效果,实际上非常简单,就是listView中一个又一个的条目而已-.大家可以只关注一个条目. 首先展示一个条目的布局效果 <?xml version="1.0&qu

  • Android Studio Gradle插件版本与Gradle版本之间的对应关系

    1.gradle插件版本配置位置: project对应的build.gradle文件中 buildscript { repositories { jcenter() } dependencies { classpath 'com.android.tools.build:gradle:1.2.3' } } 2.gradle版本配置位置: gradle-wrapper.properties 中 distributionUrl=https\://services.gradle.org/distribu

  • Android 自定义View的构造函数详细介绍

     Android自定义View的构造函数 自定义View是Android中一个常见的需求,每个自定义的View都需要实现三个基本的构造函数,而这三个构造函数又有两种常见的写法. 第一种 每个构造函数分别调用基类的构造函数,再调用一个公共的初始化方法做额外初始化. public class MyView extends ListView { public MyView(Context context) { super(context); sharedConstructor(); } public

  • Android自定义密码输入框的简单实现过程

    目录 一.实现效果及方案 二.实现 总结 一.实现效果及方案 预期效果图: 如上图所示,要实现一个这种密码输入框的样式,原生并未提供类似的效果,所以需要自定义控件的方式实现. 预期的基础效果: 只接受数字: 支持输入加密显示: 支持删除: 密码位数可配置: 文字大小.颜色.数字框背景可配置: 方案分析: 需要解决的问题: 配置性: 输入.删除如何实现? 整体UI如何实现? 1.对于输入删除可以通过setOnKeyListener监听软件盘的事件. 2.可配置性数据可以通过自定义的属性文件配置:

  • IntelliJ IDEA(2018版)安装docker插件的详细过程

    目录 一.开发环境 二.安装docker插件 1.Idea内安装 2.下载安装包安装 三.Spring Boot 服务docker部署 1.新建一个Spring Boot工程 2.配置Dockerfile文件 3.创建docker镜像 一.开发环境 开发工具 版本 IntelliJ IDEA 2018.1.6 (Community Edition) Docker integration 181.5087.20 二.安装docker插件 1.Idea内安装 打开Idea,从File->Settin

  • docker安装RabbitMQ及安装延迟插件的详细过程

    目录 1.首先说一下什么是MQ 1.1为什么要用MQ/MQ有什么用 1.1.1流量消峰 1.1.2应用解耦 1.1.3异步处理 2.安装RabbitMq 2.1首先拉取镜像 2.2启动镜像 2.3启动 rabbitmq_management (RabbitMQ后台管理) 2.3.1打开RabbitMQweb界面 3.插件下载并安装 安装完成后用工具将插件文件上传到服务器上 我这个安装攻略首先得保证服务器上安装过docker了 如果没安装docker请先去安装docker 1.首先说一下什么是MQ

  • 详解Android使用Gradle统一配置依赖管理

    在介绍使用 Gradle 统一配置依赖管理前我们先来简单介绍一下 Gradle, Gradle 是一个基于 JVM 的构建工具,也是一款非常灵活强大的构建工具,支持  jcenter.maven.Ivy 仓库,支持传递性依赖管理(即 A 依赖 B,B 依赖 C,那么 A 也就可以依赖 C,不用再单独去依赖),而不需要远程仓库或者是 pom.xml 和 ivy.xml 配置文件,抛弃了各种繁琐,基于 Groovy,build 脚本使用 Groovy 编写 而在我们的 Android studio

随机推荐