项目中打包经常遇到混淆导致的各种 bug(崩溃、闪退、无厘头),提醒过开发数次,问题还是时而发生。这时,人是不可靠的,错误时而发生,所以做了这么个脚本,旨在抛砖引玉。
目的在于扫描项目,判断是否有实体被混淆。
说明:我们项目中出现最多的问题就是实体被混淆,所以这个脚本只是扫描实体的混淆情况。不排除其他混淆导致的问题,这里只是抛砖引玉,希望通过这个思路,让有被混淆困扰的童鞋能够做好这一块。
检测通过:
Checked pass.
Time: 0.01 s
检测不通过(有实体被混淆):
Errors, has some entities be garble.
com.s.toutiao.entity
Time: 0.01 s
FATAL EXCEPTION: main
Process: com.s.d, PID: 30138
java.lang.NullPointerException: Attempt to invoke interface method 'java.lang.String java.lang.CharSequence.toString()' on a null object reference
at com.s.widget.PagerSlidingTabStrip.a(Unknown Source)
at com.s.widget.PagerSlidingTabStrip.setViewPager(Unknown Source)
at com.s.toutiao.fragment.ToutiaoFragment$4.onComplete(Unknown Source)
at com.y.http.async.HttpRequest$1.handleMessage(Unknown Source)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:158)
at android.app.ActivityThread.main(ActivityThread.java:7225)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1230)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1120)
在build.gradle加入下列代码
android.applicationVariants.all { variant ->
if (variant.name.contains("release")) {
def cmd ="python ScanProguard.py 1"
Process p = cmd.execute()
def result = p.text
if (result.contains("Errors")) {
throw new RuntimeException("下列实体被混淆了:\n" + result)
}
}
}
ScanProguard.py 脚本放在 build.gradle 同级目录
编译失败的截图
当然不能混淆了,实体混淆后就变成 abc 之流了,与接口返回的字段就对应不上,肯定会有问题。
#!/usr/bin/evn python
# -*- coding:utf-8 -*-
# FileName ScanProguard.py
# Author: HeyNiu
# Created Time: 2016/11/28
"""
扫描项目实体是否被混淆
1.传入项目路径,扫描出所有路径
2.符合实体类的路径存入列表
3.与混淆配置文件对比
4.打印被混淆的实体类
"""
import os
import time
import sys
temp = sys.argv[1]
class ScanProguard(object):
def __init__(self, project):
if not isinstance(project, dict):
raise TypeError('Project object must be dict.')
for value in project.values():
if not os.path.exists(value):
raise FileNotFoundError('%s' % value)
self.project_path = project['project_path']
self.proguard_path = project['proguard_path']
self.nim_path = ''
if 'nim_path' in project.keys():
self.nim_path = project['nim_path']
@staticmethod
def __filter_dirs(target_path, dir_name):
"""
获取目标地址目录下的文件夹列表
:param dir_name:过滤文件夹名字
:return:
"""
return (os.path.join(root, d) for root, dirs, files in os.walk(target_path) for d in dirs if
dir_name.upper() in d.upper())
def __get_project_entity(self):
"""
获取将要进行匹配的项目实体
:return:
"""
files = self.__filter_dirs(self.project_path, 'Entity')
return [str(i.split('\java\\')[-1]).replace('\\', '.') for i in files]
def __get_nim_entity(self):
"""
获取将要进行匹配的nim实体
:return:
"""
files = self.__filter_dirs(self.nim_path, 'Entity')
return [str(i.split('\java\\')[-1]).replace('\\', '.') for i in files]
def __get_proguard_entity(self):
"""
获取将要进行匹配的项目混淆文件实体
:return:
"""
l = open(self.proguard_path, encoding='utf-8').readlines()
return [i.replace('-keep class ', '').replace('.** {*;}', '').replace('.** {*;}', '').strip() for i in l
if 'ENTITY' in i.upper() and '-KEEP CLASS' in i.upper()]
def print_entity(self):
"""
打印被混淆的实体类
:return:
"""
project_entity = self.__get_project_entity()
proguard_entity = self.__get_proguard_entity()
nim_entity = self.__get_nim_entity()
for i in nim_entity:
project_entity.append(i)
l = set(project_entity).difference(set(proguard_entity))
if len(l) > 0:
print('Errors, has some entities be garble.')
for i in l:
print(i)
else:
print('Checked pass.')
class Project:
"""
这里传的就是项目路径,为了方便写成了这样
"""
document_path = os.path.join(os.path.expanduser('~'), 'Documents')
jz = ''
zf = ''
zx = ''
pro = 'proguard-project.pro'
java = 'src\main\java'
J = {
'proguard_path': os.path.join(document_path, jz, jz, 'proguard-rules.pro'),
'project_path': os.path.join(document_path, jz, jz, java, 's'),
'nim_path': os.path.join(document_path, jz, 'im', java, 'com')
}
ZF = {
'proguard_path': os.path.join(document_path, zf, zf, pro),
'project_path': os.path.join(document_path, zf, zf, java, 'com'),
'nim_path': os.path.join(document_path, zf, 'im', java, 'com')
}
XIU = {
'proguard_path': os.path.join(document_path, zx, 'D', 'proguard-project.txt'),
'project_path': os.path.join(document_path, zx, 'D', java, 'com')
}
if __name__ == '__main__':
start = time.clock()
if '1' == temp:
print('A项目')
s = ScanProguard(Project.J)
s.print_entity()
if '2' == temp:
print('B项目')
s = ScanProguard(Project.ZF)
s.print_entity()
if '3' == temp:
print('C项目')
s = ScanProguard(Project.XIU)
s.print_entity()
end = time.clock()
print("Time: %.02f s" % (end - start))
如果有更好的方法或者其他建议,欢迎评论,请轻拍。