Java Web版的Gradle编译Android工程

作者: Vghh | 来源:发表于2019-06-18 16:27 被阅读5次

先看完 Java Web版的Android反编译、重打包、签名、zipalign一条龙 :
https://www.jianshu.com/p/0ed63de7acfc

Java Web版的Android反编译、重打包、签名、zipalign一条龙:
要实现在java web中使用apktool等工具进行反编译、签名、重打包、zipalign,必须先实现java代码中嵌入CMD命令

Java Web版的Gradle编译Android工程:
要实现在java web中使用gradle等工具进行编译、签名、打包,必须先实现java代码中嵌入gradle的CMD命令。
必须在服务器配置JDK环境变量,最好是将gradle文件和工程文件绑在一起,不再额外配置环境变量。

先来了解什么是gradle?

Gradle是一个基于Apache Ant和Apache Maven概念的项目自动化构建开源工具。它使用一种基于Groovy的特定领域语言(DSL)来声明项目设置,抛弃了基于XML的各种繁琐配置。
面向Java应用为主。当前其支持的语言限于Java、Groovy、Kotlin和Scala,计划未来将支持更多的语言。

功能
Ø gradle对多工程的构建支持很出色,工程依赖是gradle的第一公民。
Ø gradle支持局部构建。
  Ø 支持多方式依赖管理:包括从maven远程仓库、nexus私服、ivy仓库以及本地文件系统的jars或者dirs
Ø gradle是第一个构建集成工具,与ant、maven、ivy有良好的相容相关性。
Ø 轻松迁移:gradle适用于任何结构的工程,你可以在同一个开发平台平行构建原工程和gradle工程。通常要求写相关测试,以保证开发的插件的相似性,这种迁移可以减少破坏性,尽可能的可靠。这也是重构的最佳实践。
Ø gradle的整体设计是以作为一种语言为导向的,而非成为一个严格死板的框架。
Ø 免费开源

gradle提供了什么

  1. 一种可切换的,像maven一样的基于约定的构建框架,却又从不锁住你(约定优于配置)
  2. 强大的支持多工程的构建
  3. 强大的依赖管理(基于Apache Ivy),提供最大的便利去构建你的工程
  4. 全力支持已有的Maven或者Ivy仓库基础建设
  5. 支持传递性依赖管理,在不需要远程仓库和pom.xml和ivy配置文件的前提下
  6. 基于groovy脚本构建,其build脚本使用groovy语言编写
  7. 具有广泛的领域模型支持你的构建

用死丢丢创建工程的时候,会在工程下生成gradle目录:
将gradle下的gradle-wrapper.jar放到libs,查看源码

在这里插入图片描述
gradle-wrapper.properties内容如下:
指引着我们如何找到将gradle文件和工程文件绑在一起,也就是自定义gradle目录
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-5.1.1-all.zip

搜索GRADLE_USER_HOME,找到如下代码

public class GradleUserHomeLookup {
    public static final String DEFAULT_GRADLE_USER_HOME = System.getProperty("user.home") + "/.gradle";
    public static final String GRADLE_USER_HOME_PROPERTY_KEY = "gradle.user.home";
    public static final String GRADLE_USER_HOME_ENV_KEY = "GRADLE_USER_HOME";

    public GradleUserHomeLookup() {
    }

    public static File gradleUserHome() {
        String gradleUserHome;
        if ((gradleUserHome = System.getProperty("gradle.user.home")) != null) {
            return new File(gradleUserHome);
        } else {
        //GRADLE_USER_HOME其实是用户配置的系统环境变量,假如用户未配置,默认返回System.getProperty("user.home") + "/.gradle"
            return (gradleUserHome = System.getenv("GRADLE_USER_HOME")) != null ? new File(gradleUserHome) : new File(DEFAULT_GRADLE_USER_HOME);
        }
    }
}

看到System.getProperty("user.home") + "/.gradle",感觉非常熟悉,就是如下玩意:

在这里插入图片描述
在这里插入图片描述
由此可知:
distributionBase=GRADLE_USER_HOME
zipStoreBase=GRADLE_USER_HOME
配置了Gradle根目录
distributionPath=wrapper/dists
zipStorePath=wrapper/dists
配置了Gradle子目录,然后里面放置了gradle文件
GRADLE_USER_HOME其实是用户配置的系统环境变量,假如用户未配置,默认返回System.getProperty("user.home") + "/.gradle"

继续搜索GRADLE_USER_HOME找到如下代码:
看见了希望,WrapperConfiguration相当于一个bean类,用来配置gradle-wrapper.properties内容

public class WrapperConfiguration {
    private URI distribution;
    private String distributionBase = "GRADLE_USER_HOME";//这里设置了默认值
    private String distributionPath = "wrapper/dists";//这里设置了默认值
    private String distributionSha256Sum;
    private String zipBase = "GRADLE_USER_HOME";//这里设置了默认值
    private String zipPath = "wrapper/dists";//这里设置了默认值

    public WrapperConfiguration() {
    }

    public URI getDistribution() {
        return this.distribution;
    }

    public void setDistribution(URI distribution) {
        this.distribution = distribution;
    }

    public String getDistributionBase() {
        return this.distributionBase;
    }

    public void setDistributionBase(String distributionBase) {
        this.distributionBase = distributionBase;
    }

    public String getDistributionPath() {
        return this.distributionPath;
    }

    public void setDistributionPath(String distributionPath) {
        this.distributionPath = distributionPath;
    }

    public String getDistributionSha256Sum() {
        return this.distributionSha256Sum;
    }

    public void setDistributionSha256Sum(String distributionSha256Sum) {
        this.distributionSha256Sum = distributionSha256Sum;
    }

    public String getZipBase() {
        return this.zipBase;
    }

    public void setZipBase(String zipBase) {
        this.zipBase = zipBase;
    }

    public String getZipPath() {
        return this.zipPath;
    }

    public void setZipPath(String zipPath) {
        this.zipPath = zipPath;
    }
}

搜索setZipBase找到如下代码:
this.config.setZipBase(this.getProperty("zipStoreBase", this.config.getZipBase()));
说明用户配置了参数,就用用户配置的参数,如果未配置,就默认。

public class WrapperExecutor {
    public static final String DISTRIBUTION_URL_PROPERTY = "distributionUrl";
    public static final String DISTRIBUTION_BASE_PROPERTY = "distributionBase";
    public static final String DISTRIBUTION_PATH_PROPERTY = "distributionPath";
    public static final String DISTRIBUTION_SHA_256_SUM = "distributionSha256Sum";
    public static final String ZIP_STORE_BASE_PROPERTY = "zipStoreBase";
    public static final String ZIP_STORE_PATH_PROPERTY = "zipStorePath";
    private final Properties properties;
    private final File propertiesFile;
    private final WrapperConfiguration config = new WrapperConfiguration();

 
    WrapperExecutor(File propertiesFile, Properties properties) {
        this.properties = properties;
        this.propertiesFile = propertiesFile;
        if (propertiesFile.exists()) {
            try {
                loadProperties(propertiesFile, properties);
                this.config.setDistribution(this.prepareDistributionUri());
                this.config.setDistributionBase(this.getProperty("distributionBase", this.config.getDistributionBase()));
                this.config.setDistributionPath(this.getProperty("distributionPath", this.config.getDistributionPath()));
                this.config.setDistributionSha256Sum(this.getProperty("distributionSha256Sum", this.config.getDistributionSha256Sum(), false));
                this.config.setZipBase(this.getProperty("zipStoreBase", this.config.getZipBase()));
                this.config.setZipPath(this.getProperty("zipStorePath", this.config.getZipPath()));
            } catch (Exception var4) {
                throw new RuntimeException(String.format("Could not load wrapper properties from '%s'.", propertiesFile), var4);
            }
        }

    }



有set,必定就有get
搜索getZipBase找到如下代码:

public class PathAssembler {
    public static final String GRADLE_USER_HOME_STRING = "GRADLE_USER_HOME";
    public static final String PROJECT_STRING = "PROJECT";
    private File gradleUserHome;

    public PathAssembler() {
    }

    public PathAssembler(File gradleUserHome) {
        this.gradleUserHome = gradleUserHome;
    }

    public PathAssembler.LocalDistribution getDistribution(WrapperConfiguration configuration) {
        String baseName = this.getDistName(configuration.getDistribution());
        String distName = this.removeExtension(baseName);
        String rootDirName = this.rootDirName(distName, configuration);
        File distDir = new File(this.getBaseDir(configuration.getDistributionBase()), configuration.getDistributionPath() + "/" + rootDirName);
        File distZip = new File(this.getBaseDir(configuration.getZipBase()), configuration.getZipPath() + "/" + rootDirName + "/" + baseName);
        return new PathAssembler.LocalDistribution(distDir, distZip);
    }

    private String rootDirName(String distName, WrapperConfiguration configuration) {
        String urlHash = this.getHash(configuration.getDistribution().toString());
        return distName + "/" + urlHash;
    }

    private File getBaseDir(String base) {
        if (base.equals("GRADLE_USER_HOME")) {
            return this.gradleUserHome;
        } else if (base.equals("PROJECT")) {
        //distributionBase=PROJECT,如果用户配置distributionBase为PROJECT,那么返回当前工程的根目录
       //  distributionPath=wrapper/dists
        // zipStoreBase=PROJECT
         //zipStorePath=wrapper/dists
        // distributionUrl=https\://services.gradle.org/distributions/gradle-5.1.1-all.zip,
            return new File(System.getProperty("user.dir"));
        } else {
            throw new RuntimeException("Base: " + base + " is unknown");
        }
    }

  
}

至此,终于找到了如何将Gradle文件和工程文件绑在一起,而不用配置gradle环境变量了,实现了自定义Gradle目录
distributionBase=PROJECT,如果用户配置distributionBase为PROJECT,那么返回当前工程的根目录
distributionPath=wrapper/dists
zipStoreBase=PROJECT
zipStorePath=wrapper/dists
distributionUrl=https://services.gradle.org/distributions/gradle-5.1.1-all.zip,

自定义Gradle目录方法:
找到系统盘的.gradle/wrapper/dists目录,将某个版本的gradle文件夹,如gradle-5.1.1-all复制到项目工程下,
注意路径一定要对应正确,zipStorePath=wrapper/dists 可以自定义如:zipStorePath=myGradle

注意:distributionUrl=https://services.gradle.org/distributions/gradle-5.1.1-all.zip 版本一定要对应

在这里插入图片描述
在这里插入图片描述

那现在需要做的就是将gradlew命令嵌入JAVA代码,调用,并且获取日志信息。

先看完 Java Web版的Android反编译、重打包、签名、zipalign一条龙 :
https://www.jianshu.com/p/0ed63de7acfc

关键代码如下:
E:\AndroidStudioWorkspace\GradlewCmd 工程根目录,小编此处未用代码获取,直接写死的。

public class CmdTest {
    public static void main(String[] args) {
        try {
            final String OPT = "app:ryrtyutuyt";
            Process process = Runtime.getRuntime().exec("E:\\AndroidStudioWorkspace\\GradlewCmd\\gradlew.bat " + OPT);
            ProcessLogRunnable infoLogRunnable = new ProcessLogRunnable();
            ProcessLogRunnable errorLogRunnable = new ProcessLogRunnable();
            infoLogRunnable.setInputStream(process.getInputStream())
                    .setOpt(OPT)
                    .setInfo(true)
                    .setEndFlag("BUILD SUCCESSFUL")
                    .setIoUtils(new IOUtils());
            Thread thread_info = new Thread(infoLogRunnable);

            //????????????????????????????????????????????????????????????????????????????????????
            errorLogRunnable.setInputStream(process.getErrorStream())
                    .setOpt(OPT)
                    .setInfo(false)
                    .setEndFlag("BUILD FAILED")
                    .setIoUtils(new IOUtils());
            Thread thread_error = new Thread(errorLogRunnable);

            thread_info.start();
            thread_error.start();

            try {
                thread_info.join();
                thread_error.join();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private static class ProcessLogRunnable implements Runnable {
        private InputStream inputStream;
        private IOUtils ioUtils;
        private String opt;
        private String endFlag;
        private boolean isInfo = true;

        public ProcessLogRunnable() {

        }

        public ProcessLogRunnable setInputStream(InputStream inputStream) {
            this.inputStream = inputStream;
            return this;
        }

        public ProcessLogRunnable setIoUtils(IOUtils ioUtils) {
            this.ioUtils = ioUtils;
            return this;
        }

        public ProcessLogRunnable setOpt(String opt) {
            this.opt = opt;
            return this;
        }

        public ProcessLogRunnable setInfo(boolean info) {
            isInfo = info;
            return this;
        }

        public ProcessLogRunnable setEndFlag(String endFlag) {
            this.endFlag = endFlag;
            return this;
        }

        @Override
        public void run() {
            ioUtils.readL_N2String(inputStream, new IOListener<String>() {
                @Override
                public void onCompleted(String result) {
                    if (isInfo) {
                        if (result.contains(endFlag)) {
                            System.out.println(opt + "成功");
                        } else {
                            System.out.println(opt + "失败");

                        }
                    } else {
                        if (result.contains(endFlag)) System.out.println(opt + "失败");
                    }

                }

                @Override
                public void onLoding(String readedPart, long current, long length) {
                    System.out.println((isInfo ? "info:" : "error") + readedPart);
                }

                @Override
                public void onInterrupted() {
                    System.out.println(opt + "失败,过程被打断");
                }

                @Override
                public void onFail(String errorMsg) {
                    System.out.println(opt + "失败" + errorMsg);
                }
            });
        }
    }


}

测试:
编译成功的输出


在这里插入图片描述

编译失败的输出


在这里插入图片描述
public class IOUtils {
    private boolean isRunning = true;

    private long contentLength = 0;
    private String encodeType = "utf-8";

    public IOUtils() {
        isRunning = true;
    }

    public IOUtils setContentLength(long contentLength) {
        this.contentLength = contentLength;
        return this;
    }

    public IOUtils setEncodeType(String encodeType) {
        this.encodeType = encodeType;
        return this;

    }

    public static void close(Closeable closeable) {
        if (closeable != null) {
            try {
                closeable.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    public void stop() {
        this.isRunning = false;
    }

    public void read(boolean isLine, InputStream inputStream, IOListener ioListener) {
        if (isLine) {
            readLine2String(inputStream, ioListener);
        } else {
            read2String(inputStream, ioListener);

        }
    }

    /**
     * @param inputStream
     * @param ioListener
     */


    public void read2String(InputStream inputStream, IOListener ioListener) {

        if (!(inputStream instanceof BufferedInputStream)) {
            inputStream = new BufferedInputStream(inputStream);
        }
        BufferedReader bufferedReader = null;
        InputStreamReader inputStreamReader = null;
        try {
            inputStreamReader = new InputStreamReader(inputStream, encodeType);
            bufferedReader = new BufferedReader(inputStreamReader);

            StringBuilder sb = new StringBuilder();

            char[] buf = new char[1024];
            int len = 0;
            long current = 0;

            while (isRunning && (len = bufferedReader.read(buf)) != -1) {
                sb.append(buf, 0, len);
                current += len;
                ioListener.onLoding("", current, contentLength);
            }

            //中断
            if (len != -1) {
                ioListener.onInterrupted();
            } else {

                ioListener.onCompleted(sb.toString());

            }

        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
            ioListener.onFail(e.getMessage());
        } catch (IOException e) {
            e.printStackTrace();
            ioListener.onFail(e.getMessage());

        } finally {
            close(bufferedReader);
            close(inputStreamReader);
            close(inputStream);
        }
    }

    /**
     * 一行一行地读
     *
     * @param inputStream
     * @param ioListener
     */
    public void readLine2String(InputStream inputStream, IOListener ioListener) {

        BufferedReader bufferedReader = null;
        InputStreamReader inputStreamReader = null;
        try {
            inputStreamReader = new InputStreamReader(inputStream, encodeType);
            bufferedReader = new BufferedReader(inputStreamReader);

            StringBuilder sb = new StringBuilder();
            long current = 0;

            String str;
            while (isRunning && (str = bufferedReader.readLine()) != null) {
                sb.append(str);
                current += str.length();

                ioListener.onLoding(str, current, contentLength);

            }

            //中断
            if ((str = bufferedReader.readLine()) != null) {
                ioListener.onInterrupted();
            } else {

                ioListener.onCompleted(sb.toString());

            }

        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
            ioListener.onFail(e.getMessage());
        } catch (IOException e) {
            e.printStackTrace();
            ioListener.onFail(e.getMessage());

        } finally {
            close(bufferedReader);
            close(inputStreamReader);
            close(inputStream);
        }
    }
    /**
     * 一行一行地读,不拼接
     *
     * @param inputStream
     * @param ioListener
     */
    public  void readL2StrNoBuffer(InputStream inputStream, IOListener ioListener) {

        BufferedReader bufferedReader = null;
        InputStreamReader inputStreamReader = null;
        try {
            inputStreamReader = new InputStreamReader(inputStream, encodeType);
            bufferedReader = new BufferedReader(inputStreamReader);

            long current = 0;

            String str;
            while (isRunning && (str = bufferedReader.readLine()) != null) {
                current += str.length();

                ioListener.onLoding(str, current, contentLength);

            }

            //中断
            if ((str = bufferedReader.readLine()) != null) {
                ioListener.onInterrupted();
            } else {

                ioListener.onCompleted("");

            }

        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
            ioListener.onFail(e.getMessage());
        } catch (IOException e) {
            e.printStackTrace();
            ioListener.onFail(e.getMessage());

        } finally {
            close(bufferedReader);
            close(inputStreamReader);
            close(inputStream);
        }
    }
    /**
     * 一行一行地读,\n拼接
     *
     * @param inputStream
     * @param ioListener
     */
    public void readL_N2String(InputStream inputStream, IOListener ioListener) {

        BufferedReader bufferedReader = null;
        InputStreamReader inputStreamReader = null;
        try {
            inputStreamReader = new InputStreamReader(inputStream, encodeType);
            bufferedReader = new BufferedReader(inputStreamReader);

            StringBuilder sb = new StringBuilder();
            long current = 0;

            String str;
            while (isRunning && (str = bufferedReader.readLine()) != null) {
                sb.append(str);
                sb.append("\n");
                current += str.length();

                ioListener.onLoding(str, current, contentLength);

            }

            //中断
            if ((str = bufferedReader.readLine()) != null) {
                ioListener.onInterrupted();
            } else {

                ioListener.onCompleted(sb.toString());

            }

        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
            ioListener.onFail(e.getMessage());
        } catch (IOException e) {
            e.printStackTrace();
            ioListener.onFail(e.getMessage());

        } finally {
            close(bufferedReader);
            close(inputStreamReader);
            close(inputStream);
        }
    }

    /**
     * 读取到文件
     *
     * @param inputStream
     * @param outputStream
     * @param ioListener
     */
    public void read2File(InputStream inputStream, OutputStream outputStream, IOListener ioListener) {
        try {

            byte[] buffer = new byte[1024];
            int len = 0;
            long current = 0;

            while (isRunning && (len = inputStream.read(buffer)) != -1) {

                outputStream.write(buffer, 0, len);
                current += len;
                ioListener.onLoding(new String(buffer), current, contentLength);
            }

            outputStream.flush();
            //中断
            if (len != -1) {
                ioListener.onInterrupted();
            } else {

                ioListener.onCompleted(null);

            }

        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            close(outputStream);
            close(inputStream);
        }
    }


}

public interface IOListener<T> {
    public void onCompleted(T result);
    public void onLoding(T readedPart, long current, long length);
    public void onInterrupted();
    public void onFail(String errorMsg);
}

先看完 Java Web版的Android反编译、重打包、签名、zipalign一条龙 :
https://www.jianshu.com/p/0ed63de7acfc

这片文章写了Java Web版的操作,喜欢的朋友可以去看看。

各位老铁有问题欢迎及时联系、指正、批评、撕逼

Github:
https://github.com/AnJiaoDe
简书:
https://www.jianshu.com/u/b8159d455c69

微信公众号


这里写图片描述

QQ群


这里写图片描述

相关文章

网友评论

    本文标题:Java Web版的Gradle编译Android工程

    本文链接:https://www.haomeiwen.com/subject/bkafqctx.html