1010import signal
1111import argparse
1212import re
13+ import xml .etree .ElementTree as ET
1314
1415def 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 )
131169if 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"
135174start_cmd = f"{ adb } shell am start -n { package_name } /{ activity_name } "
136175
137176# Get environment variables
0 commit comments