forked from orhanobut/scripts
-
Notifications
You must be signed in to change notification settings - Fork 0
/
apk_info.py
executable file
·119 lines (89 loc) · 4.11 KB
/
apk_info.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
#!/usr/bin/python
import os
import shlex
import subprocess
import re
import logging
class ApkInfo:
@staticmethod
def fetch(main_module, build_variant):
try:
# look for the apk file path
apk_path = look_for_apk_file(main_module, build_variant)
if len(apk_path) is 0:
raise Exception('Can\'t find apk for build variant={}'.format(build_variant))
# method count
classes_dex_folder = os.path.join(main_module, 'build', 'intermediates', 'dex', *build_variant.split('-'))
classes_dex_path = classes_dex_folder + '/classes.dex'
if not os.path.exists(classes_dex_path):
# >= 1.5.0
classes_dex_folder = os.path.join(main_module, 'build', 'intermediates', 'transforms', 'dex', *build_variant.split('-'))
classes_dex_path = classes_dex_folder + '/folders/1000/1f/main/classes.dex'
method_count = subprocess.Popen(
'cat ' + classes_dex_path + ' | head -c 92 | tail -c 4 | hexdump -e \'1/4 "%d\n"\'',
shell=True,
stdout=subprocess.PIPE
).stdout.read()
method_count = long(method_count)
# Apk size
apk_size = to_mb(os.path.getsize(apk_path))
# Permissions
cmd_perms = "aapt d permissions {}".format(apk_path)
permissions = subprocess.check_output(shlex.split(cmd_perms)).split("\n")
# App id
app_id = permissions[0].split(':')[1][1:]
del permissions[0]
# Beautify permissions
regex = re.compile("name=\'(\S+)\'")
permissions = [m.group(1) for l in permissions for m in [regex.search(l)] if m]
# Min sdk
min_sdk = sdk_version(apk_path, 'minSdkVersion')
# Target sdk
target_sdk = sdk_version(apk_path, 'targetSdkVersion')
# Version Name
version_name = version_info_name(apk_path)
# Version Code
version_code = version_info_code(apk_path)
return {"apk": {'apkSize': apk_size,
'appId': app_id,
'methodCount': method_count,
'minSdk': min_sdk,
'permissions': permissions,
'targetSdk': target_sdk,
'versionCode': version_code,
'versionName': version_name,
'buildVariant': build_variant}}
except:
logging.error('Constructing Apk info failed for module={} and build_variant={}'.format(main_module, build_variant))
raise
def sdk_version(apk_path, name):
version = read_property(apk_path, name)
return int(version.split('=')[1].split(')')[1], 16)
def version_info_name(apk_path):
version_name = read_property(apk_path, 'versionName')
return version_name[version_name.index('Raw') + 6:-3]
def version_info_code(apk_path):
version_code = read_property(apk_path, 'versionCode')
return int(version_code.split('=')[1].split(')')[1], 16)
def read_property(apk_path, name):
return subprocess.Popen(
'aapt list -a ' + apk_path + ' | grep ' + name,
shell=True,
stdout=subprocess.PIPE
).stdout.read()
def to_mb(byte, bsize=1024):
return "{:.5}".format(float(byte / (bsize * bsize)))
def look_for_apk_file(main_module, build_variant):
"""
Look for the apk file in the following locations :
<main_module>/build/outputs/apk (expected default apk location)
<current_jenkins_working_directory>/output-<build_variant> (monitise-mea location)
"""
apk_path_alternatives = [os.path.join(main_module, 'build', 'outputs', 'apk'),
os.path.join(os.getcwd(), 'output-' + build_variant)]
for alt in apk_path_alternatives:
if os.path.exists(alt):
apk_file = [i for i in os.listdir(alt) if re.match(r'.*' + build_variant + '.*.apk', i)]
if not len(apk_file) is 0:
return os.path.join(alt, apk_file[0])
return ""