先看完 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提供了什么
- 一种可切换的,像maven一样的基于约定的构建框架,却又从不锁住你(约定优于配置)
- 强大的支持多工程的构建
- 强大的依赖管理(基于Apache Ivy),提供最大的便利去构建你的工程
- 全力支持已有的Maven或者Ivy仓库基础建设
- 支持传递性依赖管理,在不需要远程仓库和pom.xml和ivy配置文件的前提下
- 基于groovy脚本构建,其build脚本使用groovy语言编写
- 具有广泛的领域模型支持你的构建
用死丢丢创建工程的时候,会在工程下生成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群
这里写图片描述
网友评论