4747# does.
4848DEFAULT_SDK_TAG = '6514223'
4949
50- DEFAULT_ARCH = ' armeabi-v7a'
50+ DEFAULT_ARCHS = [ 'arm64-v8a' , ' armeabi-v7a']
5151
5252MSG_P4A_RECOMMENDED_NDK_ERROR = (
5353 "WARNING: Unable to find recommended Android NDK for current "
@@ -62,21 +62,28 @@ class TargetAndroid(Target):
6262 p4a_fork = 'kivy'
6363 p4a_branch = 'master'
6464 p4a_commit = 'HEAD'
65- p4a_apk_cmd = "apk --debug --bootstrap="
6665 p4a_recommended_ndk_version = None
6766 extra_p4a_args = ''
6867
6968 def __init__ (self , * args , ** kwargs ):
7069 super ().__init__ (* args , ** kwargs )
71- self ._arch = self .buildozer .config .getdefault (
72- 'app' , 'android.arch' , DEFAULT_ARCH )
70+ if self .buildozer .config .has_option (
71+ "app" , "android.arch"
72+ ) and not self .buildozer .config .has_option ("app" , "android.archs" ):
73+ self .buildozer .error ("`android.archs` not detected, instead `android.arch` is present." )
74+ self .buildozer .error ("`android.arch` will be removed and ignored in future." )
75+ self .buildozer .error ("If you're seeing this error, please migrate to `android.archs`." )
76+ self ._archs = self .buildozer .config .getlist (
77+ 'app' , 'android.arch' , DEFAULT_ARCHS )
78+ else :
79+ self ._archs = self .buildozer .config .getlist (
80+ 'app' , 'android.archs' , DEFAULT_ARCHS )
7381 self ._build_dir = join (
74- self .buildozer .platform_dir , 'build-{}' .format (self ._arch ))
82+ self .buildozer .platform_dir , 'build-{}' .format (self .archs_snake ))
7583 executable = sys .executable or 'python'
7684 self ._p4a_cmd = '{} -m pythonforandroid.toolchain ' .format (executable )
7785 self ._p4a_bootstrap = self .buildozer .config .getdefault (
7886 'app' , 'p4a.bootstrap' , 'sdl2' )
79- self .p4a_apk_cmd += self ._p4a_bootstrap
8087 color = 'always' if USE_COLOR else 'never'
8188 self .extra_p4a_args = ' --color={} --storage-dir="{}"' .format (
8289 color , self ._build_dir )
@@ -248,6 +255,10 @@ def sdkmanager_path(self):
248255 'installed' .format (sdkmanager_path )))
249256 return sdkmanager_path
250257
258+ @property
259+ def archs_snake (self ):
260+ return "_" .join (self ._archs )
261+
251262 def check_requirements (self ):
252263 if platform in ('win32' , 'cygwin' ):
253264 try :
@@ -315,6 +326,13 @@ def check_configuration_tokens(self):
315326
316327 super ().check_configuration_tokens (errors )
317328
329+ def _p4a_have_aab_support (self ):
330+ returncode = self ._p4a ("aab -h" , break_on_error = False , show_output = False )[2 ]
331+ if returncode == 0 :
332+ return True
333+ else :
334+ return False
335+
318336 def _get_available_permissions (self ):
319337 key = 'android:available_permissions'
320338 key_sdk = 'android:available_permissions_sdk'
@@ -687,6 +705,12 @@ def install_platform(self):
687705 # ultimate configuration check.
688706 # some of our configuration cannot be check without platform.
689707 self .check_configuration_tokens ()
708+ if not self ._p4a_have_aab_support ():
709+ self .buildozer .error (
710+ "This buildozer version requires a python-for-android version with AAB (Android App Bundle) support. "
711+ "Please update your pinned version accordingly."
712+ )
713+ raise BuildozerException ()
690714
691715 self .buildozer .environ .update ({
692716 'PACKAGES_PATH' : self .buildozer .global_packages_dir ,
@@ -809,33 +833,29 @@ def compile_platform(self):
809833 if local_recipes :
810834 options .append ('--local-recipes' )
811835 options .append (local_recipes )
812- self ._p4a (
813- ("create --dist_name={} --bootstrap={} --requirements={} "
814- "--arch {} {}" ).format (
815- dist_name , self ._p4a_bootstrap , requirements ,
816- self ._arch , " " .join (options )),
817- get_stdout = True )[0 ]
836+
837+ p4a_create = "create --dist_name={} --bootstrap={} --requirements={} " .format (dist_name , self ._p4a_bootstrap , requirements )
838+
839+ for arch in self ._archs :
840+ p4a_create += "--arch {} " .format (arch )
841+
842+ p4a_create += " " .join (options )
843+
844+ self ._p4a (p4a_create , get_stdout = True )[0 ]
818845
819846 def get_available_packages (self ):
820847 return True
821848
822- def get_dist_dir (self , dist_name , arch ):
823- """Find the dist dir with the given name and target arch, if one
849+ def get_dist_dir (self , dist_name ):
850+ """Find the dist dir with the given name if one
824851 already exists, otherwise return a new dist_dir name.
825852 """
826- expected_dist_name = generate_dist_folder_name (dist_name , arch_names = [arch ])
827853
828854 # If the expected dist name does exist, simply use that
829- expected_dist_dir = join (self ._build_dir , 'dists' , expected_dist_name )
855+ expected_dist_dir = join (self ._build_dir , 'dists' , dist_name )
830856 if exists (expected_dist_dir ):
831857 return expected_dist_dir
832858
833- # For backwards compatibility, check if a directory without
834- # the arch exists. If so, this is probably the target dist.
835- old_dist_dir = join (self ._build_dir , 'dists' , dist_name )
836- if exists (old_dist_dir ):
837- return old_dist_dir
838-
839859 # If no directory has been found yet, our dist probably
840860 # doesn't exist yet, so use the expected name
841861 return expected_dist_dir
@@ -848,7 +868,7 @@ def execute_build_package(self, build_cmd):
848868 # wrapper from previous old_toolchain to new toolchain
849869 dist_name = self .buildozer .config .get ('app' , 'package.name' )
850870 local_recipes = self .get_local_recipes_dir ()
851- cmd = [self .p4a_apk_cmd , "--dist_name" , dist_name ]
871+ cmd = [self .artifact_format , "--bootstrap" , self . _p4a_bootstrap , "--dist_name" , dist_name ]
852872 for args in build_cmd :
853873 option , values = args [0 ], args [1 :]
854874 if option == "debug" :
@@ -962,14 +982,16 @@ def execute_build_package(self, build_cmd):
962982 if compile_py :
963983 cmd .append ('--no-compile-pyo' )
964984
965- cmd .append ('--arch' )
966- cmd .append (self ._arch )
985+ for arch in self ._archs :
986+ cmd .append ('--arch' )
987+ cmd .append (arch )
967988
968989 cmd = " " .join (cmd )
969990 self ._p4a (cmd )
970991
971992 def get_release_mode (self ):
972- if self .check_p4a_sign_env ():
993+ # aab, also if unsigned is named as *-release
994+ if self .check_p4a_sign_env () or self .artifact_format == "aab" :
973995 return "release"
974996 return "release-unsigned"
975997
@@ -1060,8 +1082,7 @@ def _generate_whitelist(self, dist_dir):
10601082
10611083 def build_package (self ):
10621084 dist_name = self .buildozer .config .get ('app' , 'package.name' )
1063- arch = self .buildozer .config .getdefault ('app' , 'android.arch' , DEFAULT_ARCH )
1064- dist_dir = self .get_dist_dir (dist_name , arch )
1085+ dist_dir = self .get_dist_dir (dist_name )
10651086 config = self .buildozer .config
10661087 package = self ._get_package ()
10671088 version = self .buildozer .get_version ()
@@ -1078,7 +1099,7 @@ def build_package(self):
10781099 patterns = config .getlist ('app' , config_key , [])
10791100 if not patterns :
10801101 continue
1081- if self . _arch != lib_dir :
1102+ if lib_dir not in self . _archs :
10821103 continue
10831104
10841105 self .buildozer .debug ('Search and copy libs for {}' .format (lib_dir ))
@@ -1294,33 +1315,36 @@ def build_package(self):
12941315 if is_gradle_build :
12951316 # on gradle build, the apk use the package name, and have no version
12961317 packagename_src = basename (dist_dir ) # gradle specifically uses the folder name
1297- apk = u'{packagename}-{mode}.apk' .format (
1298- packagename = packagename_src , mode = mode )
1299- apk_dir = join (dist_dir , "build" , "outputs" , "apk" , mode_sign )
1318+ artifact = u'{packagename}-{mode}.{artifact_format}' .format (
1319+ packagename = packagename_src , mode = mode , artifact_format = self .artifact_format )
1320+ if self .artifact_format == "apk" :
1321+ artifact_dir = join (dist_dir , "build" , "outputs" , "apk" , mode_sign )
1322+ elif self .artifact_format == "aab" :
1323+ artifact_dir = join (dist_dir , "build" , "outputs" , "bundle" , mode_sign )
13001324 else :
13011325 # on ant, the apk use the title, and have version
13021326 bl = u'\' " ,'
13031327 apptitle = config .get ('app' , 'title' )
13041328 if hasattr (apptitle , 'decode' ):
13051329 apptitle = apptitle .decode ('utf-8' )
13061330 apktitle = '' .join ([x for x in apptitle if x not in bl ])
1307- apk = u'{title}-{version}-{mode}.apk' .format (
1331+ artifact = u'{title}-{version}-{mode}.apk' .format (
13081332 title = apktitle ,
13091333 version = version ,
13101334 mode = mode )
1311- apk_dir = join (dist_dir , "bin" )
1335+ artifact_dir = join (dist_dir , "bin" )
13121336
1313- apk_dest = u'{packagename}-{version}-{arch}-{mode}.apk ' .format (
1337+ artifact_dest = u'{packagename}-{version}-{arch}-{mode}.{artifact_format} ' .format (
13141338 packagename = packagename , mode = mode , version = version ,
1315- arch = self ._arch )
1339+ arch = self .archs_snake , artifact_format = self . artifact_format )
13161340
13171341 # copy to our place
1318- copyfile (join (apk_dir , apk ), join (self .buildozer .bin_dir , apk_dest ))
1342+ copyfile (join (artifact_dir , artifact ), join (self .buildozer .bin_dir , artifact_dest ))
13191343
13201344 self .buildozer .info ('Android packaging done!' )
13211345 self .buildozer .info (
1322- u'APK {0} available in the bin directory' .format (apk_dest ))
1323- self .buildozer .state ['android:latestapk' ] = apk_dest
1346+ u'APK {0} available in the bin directory' .format (artifact_dest ))
1347+ self .buildozer .state ['android:latestapk' ] = artifact_dest
13241348 self .buildozer .state ['android:latestmode' ] = self .build_mode
13251349
13261350 def _update_libraries_references (self , dist_dir ):
@@ -1438,6 +1462,7 @@ def cmd_deploy(self, *args):
14381462
14391463 if state .get ('android:latestmode' , '' ) != 'debug' :
14401464 self .buildozer .error ('Only debug APK are supported for deploy' )
1465+ return
14411466
14421467 # search the APK in the bin dir
14431468 apk = state ['android:latestapk' ]
@@ -1503,28 +1528,3 @@ def cmd_logcat(self, *args):
15031528def get_target (buildozer ):
15041529 buildozer .targetname = "android"
15051530 return TargetAndroid (buildozer )
1506-
1507-
1508- def generate_dist_folder_name (base_dist_name , arch_names = None ):
1509- """Generate the distribution folder name to use, based on a
1510- combination of the input arguments.
1511-
1512- WARNING: This function is copied from python-for-android. It would
1513- be preferable to have a proper interface, either importing the p4a
1514- code or having a p4a dist dir query option.
1515-
1516- Parameters
1517- ----------
1518- base_dist_name : str
1519- The core distribution identifier string
1520- arch_names : list of str
1521- The architecture compile targets
1522-
1523- """
1524- if arch_names is None :
1525- arch_names = ["no_arch_specified" ]
1526-
1527- return '{}__{}' .format (
1528- base_dist_name ,
1529- '_' .join (arch_names )
1530- )
0 commit comments