背景
公司开发的应用,有相当一部分被破解,出现了各种所谓的纯净版、破解版、无广告版,对于公司的商业化造成了不利影响,经过调研,决定采取360加固的方案。
但是有个问题,公司外发的应用往往需要多个渠道,加固之后的apkwalle打的渠道号以及签名会丢失,需要重新签名,打渠道,比较耗时耗力,作为一名爱搞事情的程序员,这种复杂重复的工作就应该交给机器去处理,类似这种工作,python往往是不二选择。
正文
通过360加固官网知道,加固工具分为windows、mac、以及linux版本,而且加固分为登录360加固保账号然后加固两个步骤。我这里安装的是win版本,安装之后的目录结构如下图:
这里面有我们执行加固命令的环境,通过网上各种水,终于找到了360加固的命令,这就为我们python自动化加固提供了可能(这步是关键,耗费了我相当一部分的时间),上面提到加固分为登录以及加固步骤,所以命令也分两条:
登录:java -jar -Dfile.encoding=UTF-8 jiagu_jar_path -login 用户名 密码
加固: java -jar -Dfile.encoding=UTF-8 jiagu_jar_path -jiagu apk_path apk_out_path
经过一番各种调试修改,在本地通过cmd执行命令成功之后,再通过python执行也成功了,接下来部署到jenkins服务器,你以为这样就OK了么?噩梦才刚刚开始,在本地调通的python脚本部署到jenkins上始终运行不成功,也没有任何日志,一开始还以为我本地安装的是pyhon3.0,而jenkins是2.0的原因,结果我本地安装2.0之后,本地还是正常的。就在束手无策的时候,钊哥提出是不是jenkins是linux平台,而我上传的360加固环境是基于windows的,结果替换之后果然一切正常了,反正总而言之是可以了。
接下来讲讲怎么使用,公司的外发项目设计到多渠道walle打包的都有一个build.py的脚本,我们从main函数看起,如下:
if __name__ == '__main__':
options = parse_options()
path = options.origin_apk_dir
number = options.number
channels = options.channels.split(',')
spec = options.spec
walle_channel_jar = options.walle_channel_jar
print_format("APK CHANNELS")
for root, dirs, files in os.walk(path):
for file in files:
filePath = os.path.join(root, file)
if filePath.endswith(".apk"):
print "[APK CHANNELS]Start to generate channel package based on: " + filePath
start_generate(filePath, number, channels, spec, walle_channel_jar)
print "[APK CHANNELS]Channel package generation is complete."
start_generate()函数是walle打包的入口函数,我们只需要在这个之前把grale生成的apk加固重新签名,然后将生成好的apk作为参数walle打包就好了,如下:
if __name__ == '__main__':
options = parse_options()
keystore_path = options.keystore_path
print "keystore_path: " + keystore_path
ks_key_alias = options.ks_key_alias
print "ks_key_alias: " + ks_key_alias
ks_pass = options.ks_pass
print "ks_pass: " + ks_pass
key_pass = options.key_pass
print "key_pass: " + key_pass
path = options.origin_apk_dir
number = options.number
channels = options.channels.split(',')
spec = options.spec
walle_channel_jar = options.walle_channel_jar
print "jiagu_path: " + jiagu_path
print_format("APK CHANNELS")
for root, dirs, files in os.walk(path):
for file in files:
filePath = os.path.join(root, file)
if filePath.endswith(".apk"):
print "[APK CHANNELS]Start to generate channel package based on: " + filePath
index = filePath.find("debug")
#debug ingnore
if filePath.find("debug")>0:
start_generate(filePath, number, channels, spec, walle_channel_jar)
else:
#jiagu
temp_result = jiagu.jiagu(jiagu_path,"15267451420","lisj10659",filePath)
print "temp_result" + temp_result
signed_apk_path = temp_result[0:temp_result.rindex('/')] + temp_result[temp_result.rindex('/'):temp_result.rindex('.')]+"_sign.apk"
print "signed_apk_path" + signed_apk_path
#sign
sign_apk(jiagu_path,keystore_path,ks_key_alias,ks_pass,key_pass,signed_apk_path,temp_result)
#generate channel apk
start_generate(signed_apk_path, number, channels, spec, walle_channel_jar)
print "[APK CHANNELS]Channel package generation is complete."
注意这里:
keystore_path = options.keystore_path
print "keystore_path: " + keystore_path
ks_key_alias = options.ks_key_alias
print "ks_key_alias: " + ks_key_alias
ks_pass = options.ks_pass
print "ks_pass: " + ks_pass
key_pass = options.key_pass
print "key_pass: " + key_pass
增加了四个用于签名的参数,需要在jenkins上配置,如下图:
配置内容如下:
-e ${WORKSPACE}/fasthdtv.jks -a fasthdtv -k 123456 -p 123456
分别对应gradle 签名配置中的 storeFile、keyAlias、storePassword、keyPassword,然后在main函数调用的parse_options(),进行解析如下:
main函数中调用了jiagu.jagu()如下图:
所以我们需要在build.py的目录下新建一个jiagu.py并且定义jiagu()函数,如下:
import os
import subprocess
def jiagu(jiagu_360_dir, username, password, apk_file):
jiagu_360_jar = '{jiagu_360_dir}/jiagu.jar'.format(jiagu_360_dir=jiagu_360_dir)
print "jiagu_360_jar"+jiagu_360_jar
# login
command_login = "java -jar -Dfile.encoding=UTF-8 {jiagu_360_jar} -login {username} {password}".format(
jiagu_360_jar=jiagu_360_jar, username=username, password=password
)
print "command_login"+command_login
login_result = subprocess.call(command_login, shell=True)
# x86 com.dangbei.settingprovoder2.support
command_config_x86 = 'java -jar -Dfile.encoding=UTF-8 {jiagu_360_jar} -config -x86'.format(
jiagu_360_jar=jiagu_360_jar)
subprocess.call(command_config_x86, shell=True)
#dest dir
jiagu_tmp = apk_file[0:apk_file.rindex('/')]
subprocess.call("chmod -R 775 {jiagu_tmp}".format(jiagu_tmp=jiagu_tmp), shell=True)
#jiagu
command_jiagu = 'java -jar -Dfile.encoding=UTF-8 {jiagu_360_jar} -jiagu {apk_file} {jiagu_tmp}'.format(
jiagu_360_jar=jiagu_360_jar, apk_file=apk_file, jiagu_tmp=jiagu_tmp)
subprocess.call(command_jiagu, shell=True)
print ("***************** command_jiagu"+command_jiagu)
print ("***************** apk_file"+apk_file)
result_file = jiagu_tmp+apk_file[apk_file.rindex('/'):apk_file.rindex('.')] + "_jiagu.apk"
print ("***************** result_file"+result_file)
for tmp in os.listdir(jiagu_tmp):
if tmp.endswith(".apk"):
full_path = jiagu_tmp + "/" + tmp
print ("***************** full_path"+full_path)
os.chmod(full_path, 775)
os.rename(full_path, result_file)
#subprocess.call("rm -R {jiagu_tmp}".format(jiagu_tmp=jiagu_tmp), shell=True)
print ('[JIAGU]jiagu completed')
return result_file
def zip_align(zip_aligned_apk, origin_apk):
command_zipalign = 'zipalign -f -v 4 {origin_apk} {zip_aligned_apk}'.format(origin_apk=origin_apk,
zip_aligned_apk=zip_aligned_apk)
subprocess.call(command_zipalign, shell=True)
os.remove(origin_apk)
print ('[ZIP ALIGN]zipaligin completed')
def print_format(content):
print ("#########################################################")
print ("# -----> {content}".format(content=content))
print ("#########################################################")
#jiagu("D:/AndroidStudioProjects/fasthdtv/app/build_script/channel/jiagu","15267451420","lisj10659","D:/AndroidStudioProjects/fasthdtv/app/build/outputs/apk/debug/app-debug.apk")
到此jenkins配置360加固脚本(python版)结束,附件为完整的buIld.py以及jiagu.py,需要的自取,根据自己的项目情况改动,手动比心!