diff --git a/.github/workflows/android.yml b/.github/workflows/android.yml index 65c8f632a..a8c89e2d4 100644 --- a/.github/workflows/android.yml +++ b/.github/workflows/android.yml @@ -27,10 +27,10 @@ jobs: run: | pip install . - run: buildozer --help - - run: buildozer init + - run: buildozer init android - name: SDK, NDK, and p4a download run: | - sed -i.bak "s/# android.accept_sdk_license = False/android.accept_sdk_license = True/" buildozer.spec + sed -i.bak "s/#android.accept_sdk_license = False/android.accept_sdk_license = True/" buildozer.spec sed -i.bak "s/#p4a.branch = master/p4a.branch = develop/" buildozer.spec buildozer android p4a -- --help # Install OS specific dependencies diff --git a/.github/workflows/ios.yml b/.github/workflows/ios.yml index 55478f9e1..6900a92f2 100644 --- a/.github/workflows/ios.yml +++ b/.github/workflows/ios.yml @@ -25,7 +25,7 @@ jobs: buildozer --help - name: Initialize buildozer in project folder run: | - buildozer init + buildozer init ios - name: Install dependencies run: | brew install autoconf automake libtool pkg-config diff --git a/buildozer/__init__.py b/buildozer/__init__.py index 635fa4c1c..e902ca9fd 100644 --- a/buildozer/__init__.py +++ b/buildozer/__init__.py @@ -6,8 +6,9 @@ ''' -__version__ = '1.5.1.dev0' +__version__ = '1.5.2.dev0' +import json from fnmatch import fnmatch import os from os import environ, walk, sep, listdir @@ -705,11 +706,64 @@ def check_root(self): def cmd_init(self, *args): '''Create an initial buildozer.spec in the current directory ''' - if exists('buildozer.spec'): + def_spec = 'default.spec' + exit_code = 1 + largs = [x.lower().replace('--', '') for x in args] + new_spec = 'buildozer.spec' + options = ('android', 'ios', 'osx') + script_path = dirname(__file__) + + if largs: + ignore_doc = len(largs) > 1 and largs[1] in ('no-docs', 'no-comments') + + if largs[0] in options: + if exists(new_spec): + buildops.file_copy(new_spec, f'{new_spec}.bak') + print(f'Made a backup of {new_spec} as {new_spec}.bak!') + else: + buildops.file_copy(join(script_path, def_spec), new_spec) + print(f'File {new_spec} created, ready to customize!') + + with open(new_spec, encoding='utf-8') as f: + old_spec = f.read() + + inject_before = old_spec.find('\n[buildozer]\n') + + with open(join(script_path, f"default-{largs[0]}.json"), encoding='utf-8') as f: + default_json = json.load(f) + + with open(new_spec, 'w', encoding='utf-8') as f: + f.write(old_spec[:inject_before - 1]) + + for app_key, app_value in default_json.items(): + if f"[{app_key}]" not in old_spec[:inject_before]: + f.write(f"\n[{app_key}]\n") + + for key, value in default_json[app_key].items(): + if key not in old_spec[:inject_before]: + f.write('\n') + + if not ignore_doc: + for doc in value['doc']: + f.write(f"# {doc}\n") + + f.write(f"#{key} = {value.get('default', '')}\n") + + f.write(old_spec[inject_before:]) + + print(f'Modified {new_spec} for use with {largs[0]}!') + exit_code = 0 + else: + print("ERROR: Valid target must be one of the following: " + f"{', '.join(options[:-1])} or {options[-1]}.") + elif exists(new_spec): print('ERROR: You already have a buildozer.spec file.') - exit(1) - buildops.file_copy(join(dirname(__file__), 'default.spec'), 'buildozer.spec') - print('File buildozer.spec created, ready to customize!') + else: + buildops.file_copy(join(script_path, def_spec), new_spec) + print(f'File {new_spec} created, ready to customize!') + exit_code = 0 + + exit(exit_code) def cmd_distclean(self, *args): '''Clean the whole Buildozer environment. diff --git a/buildozer/default-android.json b/buildozer/default-android.json new file mode 100644 index 000000000..adf63dd73 --- /dev/null +++ b/buildozer/default-android.json @@ -0,0 +1,502 @@ +{ + "app": { + "android.aars": { + "doc": [ + "(list) Android AAR archives to add" + ] + }, + "android.accept_sdk_license": { + "doc": [ + "(bool) If True, then automatically accept SDK license agreements", + "This is intended for automation only. If set to False" + ], + "default": "False" + }, + "android.activity_class_name": { + "doc": [ + "(str) Full name including package path of the Java class that implements Android Activity", + "use that parameter together with android.entrypoint to set custom Java class instead of PythonActivity" + ], + "default": "org.kivy.android.PythonActivity" + }, + "android.adb_args": { + "doc": [ + "(str) Android additional adb arguments" + ], + "default": "-H host.docker.internal" + }, + "android.add_activities": { + "doc": [ + "(list) Java classes to add as activities to the manifest" + ], + "default": "com.example.ExampleActivity" + }, + "android.add_assets": { + "doc": [ + "(list) Put these files or directories in the apk assets directory.", + "Either form may be used, and assets need not be in \"source.include_exts\".", + " Example one: `android.add_assets = source_asset_relative_path`", + " Example two: `android.add_assets = source_asset_path:destination_asset_relative_path`" + ] + }, + "android.add_compile_options": { + "doc": [ + "(list) add java compile options", + "This can for example be necessary when importing certain java libraries using the \"android.gradle_dependencies\" option", + "See https://developer.android.com/studio/write/java8-support for further information" + ], + "default": "\"sourceCompatibility = 1.8\", \"targetCompatibility = 1.8\"" + }, + "android.add_gradle_repositories": { + "doc": [ + "(list) Gradle repositories to add {can be necessary for some android.gradle_dependencies}", + " Example: `android.gradle_repositories = \"maven { url \"https://repo.spring.io/release\" }\"`" + ] + }, + "android.add_jars": { + "doc": [ + "(list) List of Java .jar files to add to the libs so that pyjnius can access their classes", + "Don't add jars that you do not need, since extra jars can slow down the build process", + "Allows wildcards matching: OUYA-ODK/libs/*.jar" + ], + "default": "foo.jar, bar.jar, path/to/more/*.jar" + }, + "android.add_libs_arm64_v8a": { + "doc": [ + "(list) Android additional libraries to copy into libs/arm64_v8a" + ], + "default": "libs/android-v8/*.so" + }, + "android.add_libs_armeabi": { + "doc": [ + "(list) Android additional libraries to copy into libs/armeabi" + ], + "default": "libs/android/*.so" + }, + "android.add_libs_armeabi_v7a": { + "doc": [ + "(list) Android additional libraries to copy into libs/armeabi_v7a" + ], + "default": "libs/android-v7/*.so" + }, + "android.add_libs_mips": { + "doc": [ + "(list) Android additional libraries to copy into libs/mips" + ], + "default": "libs/android-mips/*.so" + }, + "android.add_libs_x86": { + "doc": [ + "(list) Android additional libraries to copy into libs/x86" + ], + "default": "libs/android-x86/*.so" + }, + "android.add_packaging_options": { + "doc": [ + "(list) packaging options to add", + "See: https://developer.android.com/reference/tools/gradle-api/7.1/com/android/build/api/dsl/PackagingOptions", + "Can be necessary to solve conflicts in { gradle_dependencies }", + "Please enclose in double quotes!", + " Example: `android.add_packaging_options = \"exclude \"META-INF/common.kotlin_module\"", + " exclude \"META-INF/*.kotlin_module\"\"`" + ] + }, + "android.add_resources": { + "doc": [ + "(list) Put these files or directories in the apk res directory.", + "The option may be used in three ways, the value may contain one, zero or \":\"", + "1) A file to add to resources, legal resource names contain [\"a-z\",\"0-9\",\"_\"]", + " `android.add_resources = my_icons/all-inclusive.png:drawable/all_inclusive.png`", + "2) A directory, here \"legal_icons\" must contain resources of one kind", + " `android.add_resources = legal_icons:drawable`", + "3) A directory, here \"legal_resources\" must contain one or more directories,", + " each of a resource kind: drawable, xml, etc..", + "Example: `android.add_resources = legal_resources`" + ] + }, + "android.add_src": { + "doc": [ + "(list) List of Java files to add to the android project (can be java or a directory containing the files)" + ] + }, + "android.api": { + "doc": [ + "(int) Target Android API, should be as high as possible" + ], + "default": "35" + }, + "android.ant_path": { + "doc": [ + "(str) ANT directory (if empty, it will be automatically downloaded)" + ] + }, + "android.apptheme": { + "doc": [ + "(str) Android app theme, default is ok for Kivy-based app" + ], + "default": "@android:style/Theme.NoTitleBar" + }, + "android.archs": { + "doc": [ + "(list) The Android archs to build for, choices: `armeabi-v7a, arm64-v8a, x86, x86_64`" + ], + "default": "arm64-v8a, armeabi-v7a" + }, + "android.allow_backup": { + "doc": [ + "(bool) Enables Android auto-backup feature (Android API >=23)" + ], + "default": "True" + }, + "android.backup_rules": { + "doc": [ + "(str) XML file for custom backup rules (see official auto backup documentation)" + ] + }, + "android.blacklist_src": { + "doc": [ + "(str) Path to a custom blacklist file" + ] + }, + "android.copy_libs": { + "doc": [ + "(bool) Copy library instead of making a libpymodules.so" + ], + "default": "True" + }, + "android.debug_artifact": { + "doc": [ + "(str) The format used to package the app for debug mode (apk or aar)" + ], + "default": "apk" + }, + "android.display_cutout": { + "doc": [ + "(str) A display cutout is an area on some devices that extends into the display surface.", + "It allows for an edge-to-edge experience while providing space for important sensors on the front of the device.", + "Available options for Android API >= 28 are \"default, shortEdges, never\" and defaults to never.", + "See: https://developer.android.com/develop/ui/views/layout/display-cutout" + ], + "default": "never" + }, + "android.enable_androidx": { + "doc": [ + "(bool) Enable AndroidX support. Enable when \"android.gradle_dependencies\"", + "contains an \"androidx\" package, or any package from Kotlin source.", + "Require target API level 28 or higher" + ], + "default": "True" + }, + "android.entrypoint": { + "doc": [ + "(str) Android entry point, default is ok for Kivy-based application" + ], + "default": "org.kivy.android.PythonActivity" + }, + "android.extra_manifest_application_arguments": { + "doc": [ + "(str) Extra xml to write directly inside the tag of AndroidManifest.xml", + "use that parameter to provide a filename from where to load your custom XML arguments" + ], + "default": "./src/android/extra_manifest_application_arguments.xml" + }, + "android.extra_manifest_xml": { + "doc": [ + "(str) Extra xml to write directly inside the element of AndroidManifest.xml", + "use that parameter to provide a filename from where to load your custom XML code" + ], + "default": "./src/android/extra_manifest.xml" + }, + "android.features": { + "doc": [ + "(list) features (adds uses-feature -tags to manifest)" + ], + "default": "android.hardware.usb.host" + }, + "android.gradle_dependencies": { + "doc": [ + "(list) Gradle dependencies to add" + ] + }, + "android.home_app": { + "doc": [ + "(bool) If True, your application will be listed as a home app (launcher app)" + ], + "default": "False" + }, + "android.library_references": { + "doc": [ + "(list) Android library project to add (will be added in the { project.properties } automatically)" + ] + }, + "android.logcat_filters": { + "doc": [ + "(str) Android logcat filters to use" + ], + "default": "*:S python:D" + }, + "android.logcat_pid_only": { + "doc": [ + "(bool) Android logcat only display log for activity's pid" + ], + "default": "False" + }, + "android.manifest.intent_filters": { + "doc": [ + "(str) XML file to include as an intent filters in tag" + ] + }, + "android.manifest.launch_mode": { + "doc": [ + "(str) launchMode to set for the main activity" + ], + "default": "standard" + }, + "android.manifest.orientation": { + "doc": [ + "(str) screenOrientation to set for the main activity", + "See: https://developer.android.com/guide/topics/manifest/activity-element" + ], + "default": "fullSensor" + }, + "android.manifest_placeholders": { + "doc": [ + "(str) If you need to insert variables into your `AndroidManifest.xml` file,", + "you can do so with the manifestPlaceholders property.", + "This property takes a map of key-value pairs. (via a string)", + " Example: `android.manifest_placeholders = [myCustomUrl:\"org.kivy.customurl\"]`" + ], + "default": "[:]" + }, + "android.meta_data": { + "doc": [ + "(list) Android application meta-data to set (key=value format)" + ] + }, + "android.minapi": { + "doc": [ + "(int) Minimum API your APK / AAB will support" + ], + "default": "24" + }, + "android.ndk": { + "doc": [ + "(str) Android NDK version to use" + ], + "default": "25b" + }, + "android.ndk_api": { + "doc": [ + "(int) Android NDK API to use", + "This is the minimum API your app will support, it should usually match android.minapi" + ], + "default": "21" + }, + "android.ndk_path": { + "doc": [ + "(str) Android NDK directory (if empty, it will be automatically downloaded)" + ] + }, + "android.no-byte-compile-python": { + "doc": [ + "(bool) Skip byte compile for .py files" + ], + "default": "False" + }, + "android.numeric_version": { + "doc": [ + "(int) Overrides automatic versionCode computation (used in build.gradle)", + "This is not the same as app version and should only be edited if you know what you're doing" + ], + "default": "1" + }, + "android.ouya.category": { + "doc": [ + "(str) OUYA Console category. Should be one of `GAME or APP`", + "If you leave this blank, OUYA support will not be enabled" + ], + "default": "GAME" + }, + "android.ouya.icon.filename": { + "doc": [ + "(str) Filename of OUYA Console icon. It must be a `732x412` PNG-image" + ], + "default": "%(source.dir)s/data/ouya_icon.png" + }, + "android.permissions": { + "doc": [ + "(list) Permissions", + "(See https://python-for-android.readthedocs.io/en/latest/buildoptions.html for all the supported syntaxes and properties)" + ], + "default": "android.permission.INTERNET, (name=android.permission.WRITE_EXTERNAL_STORAGE;maxSdkVersion=18)" + }, + "android.presplash_color": { + "doc": [ + "(string) Presplash background color (for android toolchain)", + "Supported formats are: #RRGGBB #AARRGGBB or one of the following names:", + " red, blue, green, black, white, gray, cyan, magenta, yellow, lightgray,", + " darkgray, grey, lightgrey, darkgrey, aqua, fuchsia, lime, maroon, navy,", + " olive, purple, silver, teal" + ], + "default": "#FFFFFF" + }, + "android.presplash_lottie": { + "doc": [ + "(string) Presplash animation using Lottie format", + "Lottie files can be created using various tools, like Adobe After Effect or Synfig" + ], + "default": "path/to/lottie/file.json" + }, + "android.release_artifact": { + "doc": [ + "(str) The format used to package the app for release mode (aab or apk or aar)" + ], + "default": "aab" + }, + "android.res_xml": { + "doc": [ + "(list) Copy these files to src/main/res/xml/ (used with intent-filters..)" + ], + "default": "path/to/file.xml" + }, + "android.sdk": { + "doc": [ + "(int) Android SDK version to use" + ], + "default": "20" + }, + "android.sdk_path": { + "doc": [ + "(str) Android SDK directory (if empty, it will be automatically downloaded)" + ] + }, + "android.service_class_name": { + "doc": [ + "(str) Full name including package path of the Java class that implements Python Service", + "use that parameter to set custom Java class which extends PythonService" + ], + "default": "org.kivy.android.PythonService" + }, + "android.skip_update": { + "doc": [ + "(bool) If True, then skip trying to update the Android SDK", + "This can be useful to avoid excess Internet downloads or save time when an update is due and you just want to test/build your package" + ], + "default": "False" + }, + "android.uses_library": { + "doc": [ + "(list) Android shared libraries which will be added to `AndroidManifest.xml` using tag" + ] + }, + "android.wakelock": { + "doc": [ + "(bool) Indicate whether the screen should stay on" + ], + "default": "False" + }, + "android.whitelist": { + "doc": [ + "(list) Pattern to whitelist for the whole project" + ] + }, + "android.whitelist_src": { + "doc": [ + "(str) Path to a custom whitelist file" + ] + }, + "icon.adaptive_background.filename": { + "doc": [ + "(str) Adaptive icon of the application (used if Android API level is 26+ at runtime)" + ], + "default": "%(source.dir)s/data/icon_bg.png" + }, + "icon.adaptive_foreground.filename": { + "doc": [ + "(str) Adaptive icon of the application (used if Android API level is 26+ at runtime)" + ], + "default": "%(source.dir)s/data/icon_fg.png" + }, + "orientation": { + "doc": [ + "(list) Supported orientations", + "Valid options are: landscape, portrait, portrait-reverse, landscape-reverse" + ], + "default": "portrait" + }, + "p4a.branch": { + "doc": [ + "(str) python-for-android branch to use, defaults to master" + ], + "default": "master" + }, + "p4a.bootstrap": { + "doc": [ + "(str) Bootstrap to use for android builds", + "Run \"buildozer android p4a -- bootstraps\" for a list of valid values." + ], + "default": "sdl2" + }, + "p4a.commit": { + "doc": [ + "(str) python-for-android specific commit to use, defaults to HEAD, must be within p4a.branch" + ], + "default": "HEAD" + }, + "p4a.extra_args": { + "doc": [ + "(str) Extra command line arguments to pass when invoking pythonforandroid.toolchain" + ] + }, + "p4a.fork": { + "doc": [ + "(str) python-for-android fork to use in case if p4a.url is not specified, defaults to upstream (kivy)" + ], + "default": "kivy" + }, + "p4a.hook": { + "doc": [ + "(str) Filename to the hook for p4a" + ] + }, + "p4a.local_recipes": { + "doc": [ + "(str) The directory in which python-for-android should look for your own build recipes (if any)" + ] + }, + "p4a.port": { + "doc": [ + "(int) port number to specify an explicit --port= p4a argument (eg for bootstrap flask)" + ] + }, + "p4a.setup_py": { + "doc": [ + "Control passing the --use-setup-py vs --ignore-setup-py to p4a", + "\"in the future\" --use-setup-py is going to be the default behaviour in p4a, right now it is not", + "Setting this to false will pass --ignore-setup-py, true will pass --use-setup-py", + "NOTE: this is general setuptools integration, having pyproject.toml is enough, no need to generate", + "setup.py if you're using Poetry, but you need to add \"toml\" to source.include_exts." + ], + "default": "False" + }, + "p4a.source_dir": { + "doc": [ + "(str) python-for-android git clone directory" + ] + }, + "p4a.url": { + "doc": [ + "(str) python-for-android URL to use for checkout" + ] + }, + "services": { + "doc": [ + "(list) List of Android services (name:python_script)", + "Format: CLASS_NAME:SCRIPT.py[:type]", + "Type options: :foreground or :foreground:sticky. Default is background", + "Bound services are unsupported", + " Example: `MyService:service.py,AnotherService:background.py:foreground`" + ] + } + } +} \ No newline at end of file diff --git a/buildozer/default-ios.json b/buildozer/default-ios.json new file mode 100644 index 000000000..d4753f4eb --- /dev/null +++ b/buildozer/default-ios.json @@ -0,0 +1,128 @@ +{ + "app": { + "ios.app_extensions": { + "doc": [ + "(list) A Xml String specifying a extension type", + "[[\"7zip\", \"zip\"], [\"public.zip-archive\"], \"org.kivy.myappextension\"", + " \"file\", \" Extension File\", \"${MACOSX_BUNDLE_ICON_FILE}\"", + " \"http://mysite.com/myapp/extensions.html\"]" + ] + }, + "ios.camera_usage_description": { + "doc": [ + "(str) Camera Usage justification string", + "\" uses Camera to do \"" + ] + }, + "ios.codesign.allowed": { + "doc": [ + "(bool) Whether or not to sign the code" + ], + "default": "False" + }, + "ios.codesign.debug": { + "doc": [ + "(str) Name of the certificate to use for signing the debug version", + "Get a list of available identities: buildozer ios list_identities" + ], + "default": "\"iPhone Developer: ()\"" + }, + "ios.codesign.development_team.debug": { + "doc": [ + "(str) The development team to use for signing the debug version" + ], + "default": "" + }, + "ios.codesign.development_team.release": { + "doc": [ + "(str) The development team to use for signing the release version" + ], + "default": "" + }, + "ios.codesign.release": { + "doc": [ + "(str) Name of the certificate to use for signing the release version" + ], + "default": "%(ios.codesign.debug)s" + }, + "ios.ios_deploy_branch": { + "doc": [ + "(str) ios-deploy branch" + ], + "default": "1.12.2" + }, + "ios.ios_deploy_dir": { + "doc": [ + "(str) ios-deploy directory" + ], + "default": "../ios_deploy" + }, + "ios.ios_deploy_url": { + "doc": [ + "(str) ios-deploy branch" + ], + "default": "https://github.com/phonegap/ios-deploy" + }, + "ios.kivy_ios_branch": { + "doc": [ + "(str) Branch to use" + ], + "default": "master" + }, + "ios.kivy_ios_dir": { + "doc": [ + "(str) Path to a custom kivy-ios folder" + ], + "default": "../kivy-ios" + }, + "ios.kivy_ios_url": { + "doc": [ + "(str) Source for kivy-ios" + ], + "default": "https://github.com/kivy/kivy-ios" + }, + "ios.local_network_usage_description": { + "doc": [ + "(str) Justification text to be provided for being able to use local network", + "\" needs permissions to \" in your Local Area Network" + ] + }, + "ios.manifest.app_url": { + "doc": [ + "(str) URL pointing to .ipa file to be installed", + "This option should be defined along with `display_image_url` and `full_size_image_url` options" + ] + }, + "ios.manifest.display_image_url": { + "doc": [ + "(str) URL pointing to an icon (57x57px) to be displayed during download", + "This option should be defined along with `app_url` and `full_size_image_url` options" + ] + }, + "ios.manifest.full_size_image_url": { + "doc": [ + "(str) URL pointing to a large icon (512x512px) to be used by iTunes", + "This option should be defined along with `app_url` and `display_image_url` options" + ] + }, + "ios.media_usage_description": { + "doc": [ + "(str) Justification text to be provided for being able to select media", + "\" needs to access your media in order to \"" + ] + }, + "ios.viewcontroller_based_statusbar_appearance": { + "doc": [ + "(bool) Allow StatusBar to be controlled by API" + ], + "default": "False" + }, + "orientation": { + "doc": [ + "(list) Supported orientations", + "Valid options are: landscape, portrait, portrait-reverse, landscape-reverse" + ], + "default": "portrait" + } + } +} \ No newline at end of file diff --git a/buildozer/default-osx.json b/buildozer/default-osx.json new file mode 100644 index 000000000..a82d2933b --- /dev/null +++ b/buildozer/default-osx.json @@ -0,0 +1,10 @@ +{ + "app": { + "osx.kivy_version": { + "doc": [ + "Kivy version to use" + ], + "default": "2.3.1" + } + } +} \ No newline at end of file diff --git a/buildozer/default.spec b/buildozer/default.spec index ea8bc4246..1d1a232e9 100644 --- a/buildozer/default.spec +++ b/buildozer/default.spec @@ -54,380 +54,8 @@ requirements = python3,kivy # (str) Icon of the application #icon.filename = %(source.dir)s/data/icon.png -# (list) Supported orientations -# Valid options are: landscape, portrait, portrait-reverse, landscape-reverse, or all -orientation = portrait - -# (list) List of services to declare -# This is currently only relevant to Android services. -# Each service consists of a name (a valid Java class name, with the first letter capitalized) -# followed by a colon, followed by the name of the Python script (.py file) that should be -# launched. This is optionally followed by ":foreground" for foreground services or -# ":foreground:sticky" for sticky foreground services. The default is a background service. -# Bound services are not supported. -#services = NAME:ENTRYPOINT_TO_PY,NAME2:ENTRYPOINT2_TO_PY - -# -# OSX Specific -# - -# -# author = © Copyright Info - -# Kivy version to use -osx.kivy_version = 2.2.0 - -# -# Android specific -# - # (bool) Indicate if the application should be fullscreen or not -fullscreen = 0 - -# (string) Presplash background color (for android toolchain) -# Supported formats are: #RRGGBB #AARRGGBB or one of the following names: -# red, blue, green, black, white, gray, cyan, magenta, yellow, lightgray, -# darkgray, grey, lightgrey, darkgrey, aqua, fuchsia, lime, maroon, navy, -# olive, purple, silver, teal. -#android.presplash_color = #FFFFFF - -# (string) Presplash animation using Lottie format. -# see https://lottiefiles.com/ for examples and https://airbnb.design/lottie/ -# for general documentation. -# Lottie files can be created using various tools, like Adobe After Effect or Synfig. -#android.presplash_lottie = "path/to/lottie/file.json" - -# (str) Adaptive icon of the application (used if Android API level is 26+ at runtime) -#icon.adaptive_foreground.filename = %(source.dir)s/data/icon_fg.png -#icon.adaptive_background.filename = %(source.dir)s/data/icon_bg.png - -# (list) Permissions -# (See https://python-for-android.readthedocs.io/en/latest/buildoptions.html for all the supported syntaxes and properties) -#android.permissions = android.permission.INTERNET, (name=android.permission.WRITE_EXTERNAL_STORAGE;maxSdkVersion=18) - -# (list) features (adds uses-feature -tags to manifest) -#android.features = android.hardware.usb.host - -# (int) Target Android API, should be as high as possible. -#android.api = 33 - -# (int) Minimum API your APK / AAB will support. -#android.minapi = 24 - -# (int) Android SDK version to use -#android.sdk = 20 - -# (str) Android NDK version to use -#android.ndk = 23b - -# (int) Android NDK API to use. This is the minimum API your app will support, it should usually match android.minapi. -#android.ndk_api = 21 - -# (str) Android NDK directory (if empty, it will be automatically downloaded.) -#android.ndk_path = - -# (str) Android SDK directory (if empty, it will be automatically downloaded.) -#android.sdk_path = - -# (str) ANT directory (if empty, it will be automatically downloaded.) -#android.ant_path = - -# (bool) If True, then skip trying to update the Android SDK -# This can be useful to avoid excess Internet downloads or save time -# when an update is due and you just want to test/build your package -# android.skip_update = False - -# (bool) If True, then automatically accept SDK license -# agreements. This is intended for automation only. If set to False, -# the default, you will be shown the license when first running -# buildozer. -# android.accept_sdk_license = False - -# (str) Android entry point, default is ok for Kivy-based app -#android.entrypoint = org.kivy.android.PythonActivity - -# (str) Full name including package path of the Java class that implements Android Activity -# use that parameter together with android.entrypoint to set custom Java class instead of PythonActivity -#android.activity_class_name = org.kivy.android.PythonActivity - -# (str) Extra xml to write directly inside the element of AndroidManifest.xml -# use that parameter to provide a filename from where to load your custom XML code -#android.extra_manifest_xml = ./src/android/extra_manifest.xml - -# (str) Extra xml to write directly inside the tag of AndroidManifest.xml -# use that parameter to provide a filename from where to load your custom XML arguments: -#android.extra_manifest_application_arguments = ./src/android/extra_manifest_application_arguments.xml - -# (str) Full name including package path of the Java class that implements Python Service -# use that parameter to set custom Java class which extends PythonService -#android.service_class_name = org.kivy.android.PythonService - -# (str) Android app theme, default is ok for Kivy-based app -# android.apptheme = "@android:style/Theme.NoTitleBar" - -# (list) Pattern to whitelist for the whole project -#android.whitelist = - -# (bool) If True, your application will be listed as a home app (launcher app) -# android.home_app = False - -# (str) Path to a custom whitelist file -#android.whitelist_src = - -# (str) Path to a custom blacklist file -#android.blacklist_src = - -# (list) List of Java .jar files to add to the libs so that pyjnius can access -# their classes. Don't add jars that you do not need, since extra jars can slow -# down the build process. Allows wildcards matching, for example: -# OUYA-ODK/libs/*.jar -#android.add_jars = foo.jar,bar.jar,path/to/more/*.jar - -# (list) List of Java files to add to the android project (can be java or a -# directory containing the files) -#android.add_src = - -# (list) Android AAR archives to add -#android.add_aars = - -# (list) Put these files or directories in the apk assets directory. -# Either form may be used, and assets need not be in 'source.include_exts'. -# 1) android.add_assets = source_asset_relative_path -# 2) android.add_assets = source_asset_path:destination_asset_relative_path -#android.add_assets = - -# (list) Put these files or directories in the apk res directory. -# The option may be used in three ways, the value may contain one or zero ':' -# Some examples: -# 1) A file to add to resources, legal resource names contain ['a-z','0-9','_'] -# android.add_resources = my_icons/all-inclusive.png:drawable/all_inclusive.png -# 2) A directory, here 'legal_icons' must contain resources of one kind -# android.add_resources = legal_icons:drawable -# 3) A directory, here 'legal_resources' must contain one or more directories, -# each of a resource kind: drawable, xml, etc... -# android.add_resources = legal_resources -#android.add_resources = - -# (list) Gradle dependencies to add -#android.gradle_dependencies = - -# (bool) Enable AndroidX support. Enable when 'android.gradle_dependencies' -# contains an 'androidx' package, or any package from Kotlin source. -# android.enable_androidx requires android.api >= 28 -#android.enable_androidx = True - -# (list) add java compile options -# this can for example be necessary when importing certain java libraries using the 'android.gradle_dependencies' option -# see https://developer.android.com/studio/write/java8-support for further information -# android.add_compile_options = "sourceCompatibility = 1.8", "targetCompatibility = 1.8" - -# (list) Gradle repositories to add {can be necessary for some android.gradle_dependencies} -# please enclose in double quotes -# e.g. android.gradle_repositories = "maven { url 'https://repo.spring.io/release' }" -#android.add_gradle_repositories = - -# (list) packaging options to add -# see https://developer.android.com/reference/tools/gradle-api/7.1/com/android/build/api/dsl/PackagingOptions -# can be necessary to solve conflicts in gradle_dependencies -# please enclose in double quotes -# e.g. android.add_packaging_options = "exclude 'META-INF/common.kotlin_module'", "exclude 'META-INF/*.kotlin_module'" -#android.add_packaging_options = - -# (list) Java classes to add as activities to the manifest. -#android.add_activities = com.example.ExampleActivity - -# (str) OUYA Console category. Should be one of GAME or APP -# If you leave this blank, OUYA support will not be enabled -#android.ouya.category = GAME - -# (str) Filename of OUYA Console icon. It must be a 732x412 png image. -#android.ouya.icon.filename = %(source.dir)s/data/ouya_icon.png - -# (str) XML file to include as an intent filters in tag -#android.manifest.intent_filters = - -# (list) Copy these files to src/main/res/xml/ (used for example with intent-filters) -#android.res_xml = PATH_TO_FILE, - -# (str) launchMode to set for the main activity -#android.manifest.launch_mode = standard - -# (str) screenOrientation to set for the main activity. -# Valid values can be found at https://developer.android.com/guide/topics/manifest/activity-element -#android.manifest.orientation = fullSensor - -# (list) Android additional libraries to copy into libs/armeabi -#android.add_libs_armeabi = libs/android/*.so -#android.add_libs_armeabi_v7a = libs/android-v7/*.so -#android.add_libs_arm64_v8a = libs/android-v8/*.so -#android.add_libs_x86 = libs/android-x86/*.so -#android.add_libs_mips = libs/android-mips/*.so - -# (bool) Indicate whether the screen should stay on -# Don't forget to add the WAKE_LOCK permission if you set this to True -#android.wakelock = False - -# (list) Android application meta-data to set (key=value format) -#android.meta_data = - -# (list) Android library project to add (will be added in the -# project.properties automatically.) -#android.library_references = - -# (list) Android shared libraries which will be added to AndroidManifest.xml using tag -#android.uses_library = - -# (str) Android logcat filters to use -#android.logcat_filters = *:S python:D - -# (bool) Android logcat only display log for activity's pid -#android.logcat_pid_only = False - -# (str) Android additional adb arguments -#android.adb_args = -H host.docker.internal - -# (bool) Copy library instead of making a libpymodules.so -#android.copy_libs = 1 - -# (list) The Android archs to build for, choices: armeabi-v7a, arm64-v8a, x86, x86_64 -# In past, was `android.arch` as we weren't supporting builds for multiple archs at the same time. -android.archs = arm64-v8a, armeabi-v7a - -# (int) overrides automatic versionCode computation (used in build.gradle) -# this is not the same as app version and should only be edited if you know what you're doing -# android.numeric_version = 1 - -# (bool) enables Android auto backup feature (Android API >=23) -android.allow_backup = True - -# (str) XML file for custom backup rules (see official auto backup documentation) -# android.backup_rules = - -# (str) If you need to insert variables into your AndroidManifest.xml file, -# you can do so with the manifestPlaceholders property. -# This property takes a map of key-value pairs. (via a string) -# Usage example : android.manifest_placeholders = [myCustomUrl:\"org.kivy.customurl\"] -# android.manifest_placeholders = [:] - -# (bool) Skip byte compile for .py files -# android.no-byte-compile-python = False - -# (str) The format used to package the app for release mode (aab or apk or aar). -# android.release_artifact = aab - -# (str) The format used to package the app for debug mode (apk or aar). -# android.debug_artifact = apk - -# (str) A display cutout is an area on some devices that extends into the display surface. -# It allows for an edge-to-edge experience while providing space for important sensors on the front of the device. -# Available options for Android API >= 28 are "default, shortEdges, never" and defaults to never. -# Android documentation: https://developer.android.com/develop/ui/views/layout/display-cutout -#android.display_cutout = never - -# -# Python for android (p4a) specific -# - -# (str) python-for-android URL to use for checkout -#p4a.url = - -# (str) python-for-android fork to use in case if p4a.url is not specified, defaults to upstream (kivy) -#p4a.fork = kivy - -# (str) python-for-android branch to use, defaults to master -#p4a.branch = master - -# (str) python-for-android specific commit to use, defaults to HEAD, must be within p4a.branch -#p4a.commit = HEAD - -# (str) python-for-android git clone directory -#p4a.source_dir = - -# (str) The directory in which python-for-android should look for your own build recipes (if any) -#p4a.local_recipes = - -# (str) Filename to the hook for p4a -#p4a.hook = - -# (str) Bootstrap to use for android builds -# Run "buildozer android p4a -- bootstraps" for a list of valid values. -# p4a.bootstrap = sdl2 - -# (int) port number to specify an explicit --port= p4a argument (eg for bootstrap flask) -#p4a.port = - -# Control passing the --use-setup-py vs --ignore-setup-py to p4a -# "in the future" --use-setup-py is going to be the default behaviour in p4a, right now it is not -# Setting this to false will pass --ignore-setup-py, true will pass --use-setup-py -# NOTE: this is general setuptools integration, having pyproject.toml is enough, no need to generate -# setup.py if you're using Poetry, but you need to add "toml" to source.include_exts. -#p4a.setup_py = false - -# (str) extra command line arguments to pass when invoking pythonforandroid.toolchain -#p4a.extra_args = - - - -# -# iOS specific -# - -# (str) Path to a custom kivy-ios folder -#ios.kivy_ios_dir = ../kivy-ios -# Alternately, specify the URL and branch of a git checkout: -ios.kivy_ios_url = https://github.com/kivy/kivy-ios -ios.kivy_ios_branch = master - -# Another platform dependency: ios-deploy -# Uncomment to use a custom checkout -#ios.ios_deploy_dir = ../ios_deploy -# Or specify URL and branch -ios.ios_deploy_url = https://github.com/phonegap/ios-deploy -ios.ios_deploy_branch = 1.12.2 - -# (bool) Whether or not to sign the code -ios.codesign.allowed = false - -# (str) Name of the certificate to use for signing the debug version -# Get a list of available identities: buildozer ios list_identities -#ios.codesign.debug = "iPhone Developer: ()" - -# (str) The development team to use for signing the debug version -#ios.codesign.development_team.debug = - -# (str) Name of the certificate to use for signing the release version -#ios.codesign.release = %(ios.codesign.debug)s - -# (str) The development team to use for signing the release version -#ios.codesign.development_team.release = - -# (str) Justification text to be provided for being able to select media -#ios.media_usage_description = " needs to access your media in order to " - -# (str) Justification text to be provided for being able to use local network -#ios.local_network_usage_description = " needs permissions to in your Local Area Network" - -# (str) Camera Usage justification string. -#ios.camera_usage_description = " uses Camera to do " - - -# (bool) Allow StatusBar to be controlled by API -# ios.viewcontroller_based_statusbar_appearance = False - -# (str) A Xml String specifying a extension type. -#ios.app_extensions = [["7zip", "zip"], ["public.zip-archive"], "org.kivy.myappextensionfile", " Extension File", "${MACOSX_BUNDLE_ICON_FILE}", "http://mysite.com/myapp/extensions.html"], - -# (str) URL pointing to .ipa file to be installed -# This option should be defined along with `display_image_url` and `full_size_image_url` options. -#ios.manifest.app_url = - -# (str) URL pointing to an icon (57x57px) to be displayed during download -# This option should be defined along with `app_url` and `full_size_image_url` options. -#ios.manifest.display_image_url = - -# (str) URL pointing to a large icon (512x512px) to be used by iTunes -# This option should be defined along with `app_url` and `display_image_url` options. -#ios.manifest.full_size_image_url = +#fullscreen = False [buildozer] @@ -495,3 +123,11 @@ warn_on_root = 1 # buildozer --profile demo android debug # # Environment variable overrides have priority over profile overrides. +# +# For more platform specific configuration please run one of the following commands +# so this file will be updated accordingly: +# buildozer init android +# buildozer init android --no-comments +# buildozer init ios +# buildozer init ios --no-docs +# buildozer init osx \ No newline at end of file diff --git a/buildozer/targets/android.py b/buildozer/targets/android.py index cf53de33e..6a7671e1a 100644 --- a/buildozer/targets/android.py +++ b/buildozer/targets/android.py @@ -10,7 +10,7 @@ from platform import uname WSL = 'microsoft' in uname()[2].lower() -ANDROID_API = '33' +ANDROID_API = '35' ANDROID_MINAPI = '24' APACHE_ANT_VERSION = '1.9.4' @@ -18,7 +18,7 @@ # that python-for-android cannot provide a recommendation, which in # turn only happens if the python-for-android is old and probably # doesn't support any newer NDK. -DEFAULT_ANDROID_NDK_VERSION = '17c' +DEFAULT_ANDROID_NDK_VERSION = '25b' import ast from glob import glob @@ -209,7 +209,7 @@ def _sdkmanager(self, *args, **kwargs): host, port = os.environ.get(key).split(':')[-2:] command.extend(['--proxy=http', f'--proxy_host={host.strip("/")}', f'--proxy_port={port}']) break - except: + except Exception: pass if kwargs.pop('return_child', False): @@ -288,7 +288,7 @@ def check_requirements(self): if platform in ('win32', 'cygwin'): try: self._set_win32_java_home() - except: + except Exception: traceback.print_exc() self.adb_executable = join(self.android_sdk_dir, 'platform-tools', 'adb.exe') @@ -535,7 +535,7 @@ def _read_version_subdir(self, *args): for v in os.listdir(join(*args)): try: versions.append(parse(v)) - except: + except Exception: pass if not versions: self.logger.error( @@ -1318,7 +1318,7 @@ def build_package(self): self.buildozer.hook("android_pre_build_apk") self.execute_build_package(build_cmd) self.buildozer.hook("android_post_build_apk") - except: + except Exception: # maybe the hook fail because the apk is not pass @@ -1414,7 +1414,7 @@ def _update_libraries_references(self, dist_dir): try: fd.writelines((line.decode('utf-8') for line in content)) - except: + except Exception: fd.writelines(content) if content and not content[-1].endswith(u'\n'): fd.write(u'\n') diff --git a/buildozer/targets/ios.py b/buildozer/targets/ios.py index 0d2c3e230..e0ab9cc05 100644 --- a/buildozer/targets/ios.py +++ b/buildozer/targets/ios.py @@ -123,7 +123,7 @@ def install_platform(self): self.ios_dir = self.install_or_update_repo('kivy-ios', platform='ios') self.ios_deploy_dir = self.install_or_update_repo('ios-deploy', platform='ios', - branch='1.7.0', + branch='1.12.2', owner='phonegap') def toolchain(self, cmd, **kwargs): @@ -142,7 +142,7 @@ def xcodebuild(self, *args, **kwargs): @property def code_signing_allowed(self): - allowed = self.buildozer.config.getboolean("app", "ios.codesign.allowed") + allowed = self.buildozer.config.getbooldefault("app", "ios.codesign.allowed", False) allowed = "YES" if allowed else "NO" return f"CODE_SIGNING_ALLOWED={allowed}" @@ -436,7 +436,7 @@ def _create_icons(self): def check_configuration_tokens(self): errors = [] config = self.buildozer.config - if not config.getboolean('app', 'ios.codesign.allowed'): + if not config.getbooldefault('app', 'ios.codesign.allowed', False): return identity_debug = config.getdefault('app', 'ios.codesign.debug', '') identity_release = config.getdefault('app', 'ios.codesign.release', diff --git a/buildozer/targets/osx.py b/buildozer/targets/osx.py index 6b00eeb9e..a038b096b 100644 --- a/buildozer/targets/osx.py +++ b/buildozer/targets/osx.py @@ -13,6 +13,8 @@ import buildozer.buildops as buildops from buildozer.target import Target +KIVY_VERSION = '2.3.1' + class TargetOSX(Target): @@ -38,7 +40,8 @@ def ensure_sdk(self): buildops.file_remove(join(platdir, 'master.zip')) def download_kivy(self, cwd): - current_kivy_vers = self.buildozer.config.get('app', 'osx.kivy_version') + current_kivy_vers = self.buildozer.config.getdefault('app', 'osx.kivy_version', + KIVY_VERSION) if exists('/Applications/Kivy.app'): self.logger.info('Kivy found in Applications dir...') diff --git a/docs/source/quickstart.rst b/docs/source/quickstart.rst index 00151d588..c8f943d45 100644 --- a/docs/source/quickstart.rst +++ b/docs/source/quickstart.rst @@ -14,10 +14,18 @@ Init and build for Android line like :class:`__version__ = "1.0.3"` in your :class:`main.py`. Ensure you have one at the start of your application. It is not mandatory but heavily advised. -#. Create a :class:`buildozer.spec` file, with:: +#. Create a minimal :class:`buildozer.spec` file, with:: buildozer init +#. Cross-platform initialization with :class:`buildozer.spec`:: + + buildozer init android + buildozer init android --no-comments + buildozer init ios + buildozer init ios --no-docs + buildozer init osx + #. Edit the :class:`buildozer.spec` according to the :ref:`specifications`. You should at least change the :class:`title`, :class:`package.name` and :class:`package.domain` in the :class:`[app]` section. diff --git a/setup.py b/setup.py index 3d40f5200..f4e2ed40f 100644 --- a/setup.py +++ b/setup.py @@ -5,10 +5,8 @@ import sys from setuptools import setup from os.path import dirname, join -import codecs import os import re -import io here = os.path.abspath(os.path.dirname(__file__)) @@ -30,7 +28,7 @@ def find_version(*file_paths): # Open in Latin-1 so that we avoid encoding errors. # Use codecs.open for Python 2 compatibility - with codecs.open(os.path.join(here, *file_paths), 'r', 'utf-8') as f: + with open(os.path.join(here, *file_paths), encoding='utf-8') as f: version_file = f.read() # The version line must have the form @@ -43,9 +41,9 @@ def find_version(*file_paths): curdir = dirname(__file__) -with io.open(join(curdir, "README.md"), encoding="utf-8") as fd: +with open(join(curdir, "README.md"), encoding="utf-8") as fd: readme = fd.read() -with io.open(join(curdir, "CHANGELOG.md"), encoding="utf-8") as fd: +with open(join(curdir, "CHANGELOG.md"), encoding="utf-8") as fd: changelog = fd.read() setup( @@ -68,7 +66,8 @@ def find_version(*file_paths): packages=[ 'buildozer', 'buildozer.targets', 'buildozer.libs', 'buildozer.scripts' ], - package_data={'buildozer': ['default.spec']}, + package_data={'buildozer': ['default.spec', 'default-android.json', + 'default-ios.json', 'default-osx.json']}, include_package_data=True, install_requires=[ 'pexpect', @@ -79,7 +78,7 @@ def find_version(*file_paths): # here. # Restricted version because python-for-android's recipes can't handle # later versions. - 'cython<3.0' + 'cython<3.12' ], extras_require={ 'test': ['pytest'], @@ -95,6 +94,9 @@ def find_version(*file_paths): 'Programming Language :: Python :: 3.9', 'Programming Language :: Python :: 3.10', 'Programming Language :: Python :: 3.11', + 'Programming Language :: Python :: 3.12', + 'Programming Language :: Python :: 3.13', + 'Programming Language :: Python :: 3.14', ], entry_points={ 'console_scripts': [ diff --git a/tests/targets/utils.py b/tests/targets/utils.py index dd41c4fc8..fa1ba5357 100644 --- a/tests/targets/utils.py +++ b/tests/targets/utils.py @@ -1,3 +1,4 @@ +import json import os import re from unittest import mock @@ -22,8 +23,8 @@ def patch_logger_error(): return mock.patch("buildozer.logger.Logger.error") -def default_specfile_path(): - return os.path.join(os.path.dirname(buildozer_module.__file__), "default.spec") +def default_specfile_path(default='default.spec'): + return os.path.join(os.path.dirname(buildozer_module.__file__), default) def init_buildozer(temp_dir, target, options=None): @@ -41,11 +42,19 @@ def init_buildozer(temp_dir, target, options=None): if options is None: options = {} - spec_path = os.path.join(temp_dir.name, "buildozer.spec") + spec_path = os.path.join(temp_dir.name, 'buildozer.spec') - with open(default_specfile_path()) as f: + with open(default_specfile_path(), encoding='utf-8') as f: default_spec = f.readlines() + for platform in ('android', 'ios', 'osx'): + """ + Test to see if the json files are valid. If it fails, + the problem is within the json file itself. + """ + with open(default_specfile_path(f'default-{platform}.json'), encoding='utf-8') as f: + json.load(f) + spec = [] for line in default_spec: if line.strip(): @@ -56,7 +65,7 @@ def init_buildozer(temp_dir, target, options=None): spec.append(line) - with open(spec_path, "w") as f: + with open(spec_path, 'w', encoding='utf-8') as f: f.writelines(spec) return Buildozer(filename=spec_path, target=target)