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