最近,在用脚本工具进行多渠道打包的日常工作中,代码执行到jar2dex,也就是将jar包转换为dex文件的过程中,使用d8工具,会产生较多的warning日志, 虽然不是很影响转换的过程,但是对于微微有些强迫症的自己来说,还是想解决掉冗余的日志,方便把控打包进度和定位分析问题。
这里贴了一张d8工具在进行jar转dex的过程中,我们能看到,其实产生了比较多的Warning in,当然并不是说屏蔽掉Warning in, 就意味着项目中不存在这些警告信息,可能做法在部分人看来有些掩耳盗铃,但我想表达是,在项目开发维护中,一些依赖库是有较多版本的,可能新版本解决了一些问题,但是还不够稳定,对于老版本而言具备稳定,但可能或多或少有些警告,尤其在面对多渠道打包的工作中,有很多SDK,我们是没有修改权的,毕竟是第三方的渠道。因此,如何在自己能掌控的范围里,将问题解决,其实是我想表达的。
好了,废话不多说,我们先分析jar转dex的过程,其实用到2个工具,一个是dex工具,另外一个是d8工具,既然dex工具已经支持jar转dex,为什么谷歌又推出d8工具呢,其实官方给出的解释是,d8支持java8的脱糖,那什么又是脱糖呢?我们知道,一些编程语言为了编码的高效性,会有语法糖,比如kotlin的with,let,run等等,而java8新特性也不例外,这些语法糖方便了开发人员,但是在底层识别的过程中,可能会因为版本特性,导致转换编译失败,那么谷歌为了支持java8,也是在API28,也就是build-tools\28.0.2新增了d8工具,用于脱糖。
脱糖含义:lamdal表达式在打包构建期间被转换成内部类的形式,这个过程叫脱糖(java编译时不会这样)
1:dx.bat dx.jar
def jar2dex(srcDir, dstDir):
"""
compile jar files to dex.使用工具dx工具
"""
if platform.system() == 'Windows':
#--------dx工具---------
dexToolPath = file_utils.getFullToolPath("dx.bat")
cmd = '"%s" --dex --output="%s" ' % (dexToolPath, dstDir + "/classes.dex")
#cmd = '"%s" --dex --min-sdk-version=26 --output="%s" ' % (dexToolPath, dstDir + "/classes.dex")
else:
dexToolPath = file_utils.getFullToolPath("/lib/dx.jar")
cmd = file_utils.getJavaCMD() + ' -jar -Xms512m -Xmx512m "%s" --dex --output="%s" ' % (dexToolPath, dstDir + "/classes.dex")
#helper.jar
for f in os.listdir(srcDir):
if f.endswith(".jar"):
cmd = cmd + " " + os.path.join(srcDir, f)
#public.jar,channelsdk.jar
for f in os.listdir(os.path.join(srcDir, "libs")):
if f.endswith(".jar"):
cmd = cmd + " " + os.path.join(srcDir, "libs", f)
#dx.bat --dex --output=dstDir + "/classes.dex" sdk1.jar sdk2.jar......
ret = file_utils.execFormatCmd(cmd)
2:d8.bat d8.jar
def jar2dex(srcDir, dstDir):
"""
compile jar files to dex.使用d8工具
"""
if platform.system() == 'Windows':
#--------d8工具,带warning的---------
# 联想 oppo,YSDK渠道使用d8语法糖脱糖,解决lambda表达式
# print(file_utils.getFullToolPath("d8"))
cmd = file_utils.getFullToolPath("d8") + " --lib " + file_utils.getFullToolPath("android.jar") + " --output " + dstDir + " "
else:
dexToolPath = file_utils.getFullToolPath("/lib/dx.jar")
cmd = file_utils.getJavaCMD() + ' -jar -Xms512m -Xmx512m "%s" --dex --output="%s" ' % (dexToolPath, dstDir + "/classes.dex")
#helper.jar
for f in os.listdir(srcDir):
if f.endswith(".jar"):
cmd = cmd + " " + os.path.join(srcDir, f)
#public.jar,channelsdk.jar
for f in os.listdir(os.path.join(srcDir, "libs")):
if f.endswith(".jar"):
cmd = cmd + " " + os.path.join(srcDir, "libs", f)
#d8 --lib android.jar --output dstDir sdk1.jar sdk2,jar...
ret = file_utils.execFormatCmd(cmd)
在我们了解dx,d8工具后,来进入主题,那便是开始说到的,d8在使用过程中,会产生冗余日志,比较影响我们打包工具的清晰化,因此,我就在想,能不能屏蔽掉这些产生的Warning in 日志呢?
首先分析,这些Warning in来源于哪里?在jar2dex这个函数里,使用到的工具无非是d8.bat,而.bat是windows系统下的可执行文件,依赖的还是d8.jar,因此使用jadx-gui-dev.exe 反编译d8.jar后,我们全局搜索Warning in,可以看到一个接口方法里有输出,那就好办了,只要我们注释掉,再打包成jar,理论上不就可以了吗!
可问题来了,我们在jadx里看到的是.class编译后的文件,可是怎么导出呢,这里又用到了一个工具,jd-gui.exe
打开d8.jar后,点击左上角的File,然后Save All Resources,即可导出为.java文件
然后我们打开DiagnosticsHandler.java,注释掉其中的System....就可以了。
default void warning(Diagnostic warning) {
if (warning.getOrigin() != Origin.unknown()) {
//System.err.print("Warning in " + warning.getOrigin() + ":\n ");
} else {
//System.err.print("Warning: ");
}
//System.err.println(warning.getDiagnosticMessage());
}
最后一步,就是将.java重新编译生成.class文件,替换jar包,再次解压生成jar包替换即可。
我们使用javac命令,完成命令如下:
javac -cp d8.jar DiagnosticsHandler.java