Skip to content

Commit 342487e

Browse files
committed
qt-android-runner.py: support launching any activity name
Applications can potentially have their own QtActivity sub-class in which case they will be referenced in the manifest, and then trying to launch the app using QtActivity will fail. Fixes: QTBUG-138982 Pick-to: 6.8 6.9 6.10 Change-Id: Ib20199f09e1b507460b3b6a91f1e0b2a5aa2bc3f Reviewed-by: Ville Voutilainen <ville.voutilainen@qt.io>
1 parent eb0b93b commit 342487e

File tree

1 file changed

+53
-14
lines changed

1 file changed

+53
-14
lines changed

libexec/qt-android-runner.py

Lines changed: 53 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
import signal
1111
import argparse
1212
import re
13+
import xml.etree.ElementTree as ET
1314

1415
def status(msg):
1516
print(f"\n-- {msg}")
@@ -90,16 +91,42 @@ def die(msg):
9091
error(f"Failed to install the APK, received error: {e}")
9192

9293

93-
def get_package_name(build_path):
94+
def find_launcher_activity(root):
95+
ns_android = 'http://schemas.android.com/apk/res/android'
96+
android_name_attr = f'{{{ns_android}}}name'
97+
98+
for activity in root.findall('.//activity'):
99+
for intent_filter in activity.findall('intent-filter'):
100+
actions = {action.get(android_name_attr) for action in intent_filter.findall('action')}
101+
categories = {cat.get(android_name_attr) for cat in intent_filter.findall('category')}
102+
main_action = 'android.intent.action.MAIN'
103+
launcher_category = 'android.intent.category.LAUNCHER'
104+
if main_action in actions and launcher_category in categories:
105+
return activity.get(android_name_attr)
106+
return None
107+
108+
def get_manifest_app_details(manifest_file):
94109
try:
95-
manifest_file = os.path.join(args.build_path, "AndroidManifest.xml")
96-
if os.path.isfile(manifest_file):
97-
with open(manifest_file) as f:
98-
for line in f:
99-
if 'package="' in line:
100-
return line.split('package="')[1].split('"')[0]
110+
if not os.path.isfile(manifest_file):
111+
return None, None
101112

102-
gradle_file = os.path.join(args.build_path, "build.gradle")
113+
tree = ET.parse(manifest_file)
114+
root = tree.getroot()
115+
package_name = root.get("package")
116+
activity_name = find_launcher_activity(root)
117+
118+
if activity_name and activity_name.startswith('.') and package_name:
119+
activity_name = package_name + activity_name
120+
121+
return package_name, activity_name
122+
except Exception as e:
123+
error(f"Failed to parse AndroidManifest.xml, received error: {e}")
124+
return None, None
125+
126+
def get_package_from_gradle(build_path):
127+
try:
128+
# Check build.gradle for namespace
129+
gradle_file = os.path.join(build_path, "build.gradle")
103130
if os.path.isfile(gradle_file):
104131
with open(gradle_file) as f:
105132
for line in f:
@@ -111,11 +138,12 @@ def get_package_name(build_path):
111138
# namespace = 'org.qtproject.example.app'
112139
match = re.search(r"namespace\s*=?\s*['\"]([^'\"]+)['\"]", line)
113140
if match:
114-
potentialPackageName = match.group(1)
115-
if (potentialPackageName != "androidPackageName"):
116-
return potentialPackageName
141+
potential_package_name = match.group(1)
142+
if potential_package_name != "androidPackageName":
143+
return potential_package_name
117144

118-
properties_file = os.path.join(args.build_path, "gradle.properties")
145+
# Check gradle.properties for androidPackageName
146+
properties_file = os.path.join(build_path, "gradle.properties")
119147
if os.path.isfile(properties_file):
120148
with open(properties_file) as f:
121149
for line in f:
@@ -126,12 +154,23 @@ def get_package_name(build_path):
126154

127155
return None
128156

157+
def get_app_details(build_path):
158+
manifest_file = os.path.join(build_path, "AndroidManifest.xml")
159+
package_name, activity_name = get_manifest_app_details(manifest_file)
160+
161+
if not package_name:
162+
package_name = get_package_from_gradle(build_path)
163+
164+
return package_name, activity_name
165+
166+
129167
# Get app details
130-
package_name = get_package_name(args.build_path)
168+
package_name, activity_name = get_app_details(args.build_path)
131169
if not package_name:
132170
die("Failed to retrieve the package name of the app")
171+
if not activity_name:
172+
die("Failed to retrieve the main activity name of the app")
133173

134-
activity_name = "org.qtproject.qt.android.bindings.QtActivity"
135174
start_cmd = f"{adb} shell am start -n {package_name}/{activity_name}"
136175

137176
# Get environment variables

0 commit comments

Comments
 (0)