APK_NAME_PAT = re.compile(".*name='([a-zA-Z0-9._]*)'.*")
APK_VERCODE_PAT = re.compile(".*versionCode='([0-9]*)'.*")
APK_VERNAME_PAT = re.compile(".*versionName='([^']*)'.*")
-APK_LABEL_PAT = re.compile(".*label='(.*?)'(\n| [a-z]*?=).*")
-APK_ICON_PAT = re.compile(".*application-icon-([0-9]+):'([^']+?)'.*")
-APK_ICON_PAT_NODPI = re.compile(".*icon='([^']+?)'.*")
+APK_LABEL_ICON_PAT = re.compile(".*\s+label='(.*)'\s+icon='(.*)'")
APK_SDK_VERSION_PAT = re.compile(".*'([0-9]*)'.*")
APK_PERMISSION_PAT = \
re.compile(".*(name='(?P<name>.*?)')(.*maxSdkVersion='(?P<maxSdkVersion>.*?)')?.*")
APK_FEATURE_PAT = re.compile(".*name='([^']*)'.*")
screen_densities = ['65534', '640', '480', '320', '240', '160', '120']
+# resolutions must end with 'dpi'
screen_resolutions = {
"xxxhdpi": '640',
"xxhdpi": '480',
"hdpi": '240',
"mdpi": '160',
"ldpi": '120',
- "undefined": '-1',
+ "undefineddpi": '-1',
"anydpi": '65534',
"nodpi": '65535'
}
txt += "* command line: <code>" + ' '.join(sys.argv) + "</code>\n"
txt += "* started at " + common.get_wiki_timestamp(start_timestamp) + '\n'
txt += "* completed at " + common.get_wiki_timestamp() + '\n'
+ txt += common.get_git_describe_link()
txt += "\n\n"
txt += common.get_android_tools_version_log()
newpage.save(txt, summary='Run log')
'antiFeatures': set(),
}
- try:
- import androguard
- androguard # silence pyflakes
+ if common.use_androguard():
scan_apk_androguard(apk, apk_file)
- except ImportError:
+ else:
scan_apk_aapt(apk, apk_file)
# Get the signature, or rather the signing key fingerprints
return apk
+def _get_apk_icons_src(apkfile, icon_name):
+ """Extract the paths to the app icon in all available densities
+
+ """
+ icons_src = dict()
+ density_re = re.compile('^res/(.*)/' + icon_name + '\.(png|xml)$')
+ with zipfile.ZipFile(apkfile) as zf:
+ for filename in zf.namelist():
+ m = density_re.match(filename)
+ if m:
+ folder = m.group(1).split('-')
+ if len(folder) > 1 and folder[1].endswith('dpi'):
+ density = screen_resolutions[folder[1]]
+ else:
+ density = '160'
+ icons_src[density] = m.group(0)
+ if icons_src.get('-1') is None and '160' in icons_src:
+ icons_src['-1'] = icons_src['160']
+ return icons_src
+
+
def scan_apk_aapt(apk, apkfile):
p = SdkToolsPopen(['aapt', 'dump', 'badging', apkfile], output=False)
if p.returncode != 0:
else:
logging.error(_("Failed to get apk information, skipping {path}").format(path=apkfile))
raise BuildException(_("Invalid APK"))
+ icon_name = None
for line in p.output.splitlines():
if line.startswith("package:"):
try:
except Exception as e:
raise FDroidException("Package matching failed: " + str(e) + "\nLine was: " + line)
elif line.startswith("application:"):
- apk['name'] = re.match(APK_LABEL_PAT, line).group(1)
- # Keep path to non-dpi icon in case we need it
- match = re.match(APK_ICON_PAT_NODPI, line)
- if match:
- apk['icons_src']['-1'] = match.group(1)
- elif line.startswith("launchable-activity:"):
+ m = re.match(APK_LABEL_ICON_PAT, line)
+ if m:
+ apk['name'] = m.group(1)
+ icon_name = os.path.splitext(os.path.basename(m.group(2)))[0]
+ elif not apk.get('name') and line.startswith("launchable-activity:"):
# Only use launchable-activity as fallback to application
- if not apk['name']:
- apk['name'] = re.match(APK_LABEL_PAT, line).group(1)
- if '-1' not in apk['icons_src']:
- match = re.match(APK_ICON_PAT_NODPI, line)
- if match:
- apk['icons_src']['-1'] = match.group(1)
- elif line.startswith("application-icon-"):
- match = re.match(APK_ICON_PAT, line)
- if match:
- density = match.group(1)
- path = match.group(2)
- apk['icons_src'][density] = path
+ apk['name'] = re.match(APK_LABEL_ICON_PAT, line).group(1)
elif line.startswith("sdkVersion:"):
m = re.match(APK_SDK_VERSION_PAT, line)
if m is None:
if feature.startswith("android.feature."):
feature = feature[16:]
apk['features'].add(feature)
+ apk['icons_src'] = _get_apk_icons_src(apkfile, icon_name)
def scan_apk_androguard(apk, apkfile):
if apkobject.get_target_sdk_version() is not None:
apk['targetSdkVersion'] = apkobject.get_target_sdk_version()
- icon_id = int(apkobject.get_element("application", "icon").replace("@", "0x"), 16)
- icon_name = arsc.get_id(apk['packageName'], icon_id)[1]
-
- density_re = re.compile("^res/(.*)/" + icon_name + ".*$")
-
- for file in apkobject.get_files():
- d_re = density_re.match(file)
- if d_re:
- folder = d_re.group(1).split('-')
- if len(folder) > 1:
- resolution = folder[1]
- else:
- resolution = 'mdpi'
- density = screen_resolutions[resolution]
- apk['icons_src'][density] = d_re.group(0)
-
- if apk['icons_src'].get('-1') is None:
- apk['icons_src']['-1'] = apk['icons_src']['160']
+ icon_id_str = apkobject.get_element("application", "icon")
+ if icon_id_str:
+ icon_id = int(icon_id_str.replace("@", "0x"), 16)
+ icon_name = arsc.get_id(apk['packageName'], icon_id)[1]
+ apk['icons_src'] = _get_apk_icons_src(apkfile, icon_name)
arch_re = re.compile("^lib/(.*)/.*$")
arch = set([arch_re.match(file).group(1) for file in apkobject.get_files() if arch_re.match(file)])
maxSdkVersion
)
apk['uses-permission'].append(permission)
+ for name, maxSdkVersion in apkobject.get_uses_implied_permission_list():
+ permission = UsesPermission(
+ name,
+ maxSdkVersion
+ )
+ apk['uses-permission'].append(permission)
for item in xml.findall('uses-permission-sdk-23'):
name = str(item.attrib['{' + xml.nsmap['android'] + '}name'])
apk['uses-permission-sdk-23'].append(permission_sdk_23)
for item in xml.findall('uses-feature'):
- feature = str(item.attrib['{' + xml.nsmap['android'] + '}name'])
+ key = '{' + xml.nsmap['android'] + '}name'
+ if key not in item.attrib:
+ continue
+ feature = str(item.attrib[key])
if feature != "android.hardware.screen.portrait" \
and feature != "android.hardware.screen.landscape":
if feature.startswith("android.feature."):
feature = feature[16:]
- apk['features'].append(feature)
+ required = item.attrib.get('{' + xml.nsmap['android'] + '}required')
+ if required is None or required == 'true':
+ apk['features'].append(feature)
def process_apk(apkcache, apkfilename, repodir, knownapks, use_date_from_apk=False,
return True, None, False
# Check for debuggable apks...
- if common.isApkAndDebuggable(apkfile):
+ if common.is_apk_and_debuggable(apkfile):
logging.warning('{0} is set to android:debuggable="true"'.format(apkfile))
if options.rename_apks:
if density in apk['icons']:
break
if density == screen_densities[-1] or dpi >= int(density):
- apk['icons'][density] = icon_filename
+ apk['icons'][density] = icon_filename + icon_type
shutil.move(icon_path,
- os.path.join(get_icon_dir(repo_dir, density), icon_filename))
+ os.path.join(get_icon_dir(repo_dir, density), icon_filename + icon_type))
empty_densities.remove(density)
break
except Exception as e: