kivyforge 3.0.0.dev0__tar.gz → 3.0.0.dev1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (296) hide show
  1. kivyforge-3.0.0.dev1/CHANGELOG.md +1944 -0
  2. {kivyforge-3.0.0.dev0/kivyforge.egg-info → kivyforge-3.0.0.dev1}/PKG-INFO +144 -36
  3. {kivyforge-3.0.0.dev0 → kivyforge-3.0.0.dev1}/README.md +136 -28
  4. kivyforge-3.0.0.dev1/kivyforge/__init__.py +11 -0
  5. {kivyforge-3.0.0.dev0 → kivyforge-3.0.0.dev1}/kivyforge/artifacts/collect.py +31 -10
  6. {kivyforge-3.0.0.dev0 → kivyforge-3.0.0.dev1}/kivyforge/artifacts/download.py +27 -2
  7. {kivyforge-3.0.0.dev0 → kivyforge-3.0.0.dev1}/kivyforge/artifacts/wheels.py +5 -2
  8. kivyforge-3.0.0.dev1/kivyforge/build_outcome.py +111 -0
  9. kivyforge-3.0.0.dev1/kivyforge/bundle/app_metadata.py +334 -0
  10. kivyforge-3.0.0.dev1/kivyforge/bundle/casefold.py +88 -0
  11. kivyforge-3.0.0.dev1/kivyforge/bundle/pycompile.py +323 -0
  12. kivyforge-3.0.0.dev1/kivyforge/bundle/workdir.py +27 -0
  13. kivyforge-3.0.0.dev1/kivyforge/capabilities.py +147 -0
  14. {kivyforge-3.0.0.dev0 → kivyforge-3.0.0.dev1}/kivyforge/cli/__init__.py +4 -1
  15. kivyforge-3.0.0.dev1/kivyforge/cli/_common.py +171 -0
  16. kivyforge-3.0.0.dev1/kivyforge/cli/_output.py +134 -0
  17. {kivyforge-3.0.0.dev0 → kivyforge-3.0.0.dev1}/kivyforge/cli/_platform.py +32 -1
  18. kivyforge-3.0.0.dev1/kivyforge/cli/_version.py +170 -0
  19. kivyforge-3.0.0.dev1/kivyforge/cli/build.py +164 -0
  20. kivyforge-3.0.0.dev1/kivyforge/cli/capabilities.py +56 -0
  21. kivyforge-3.0.0.dev1/kivyforge/cli/clean.py +172 -0
  22. kivyforge-3.0.0.dev1/kivyforge/cli/doctor.py +142 -0
  23. {kivyforge-3.0.0.dev0 → kivyforge-3.0.0.dev1}/kivyforge/cli/init.py +283 -89
  24. {kivyforge-3.0.0.dev0 → kivyforge-3.0.0.dev1}/kivyforge/cli/init_writer.py +74 -79
  25. {kivyforge-3.0.0.dev0 → kivyforge-3.0.0.dev1}/kivyforge/cli/lock.py +152 -47
  26. kivyforge-3.0.0.dev1/kivyforge/cli/open_cmd.py +24 -0
  27. {kivyforge-3.0.0.dev0 → kivyforge-3.0.0.dev1}/kivyforge/cli/package.py +74 -27
  28. {kivyforge-3.0.0.dev0 → kivyforge-3.0.0.dev1}/kivyforge/cli/run.py +116 -6
  29. kivyforge-3.0.0.dev1/kivyforge/cli/status.py +91 -0
  30. {kivyforge-3.0.0.dev0 → kivyforge-3.0.0.dev1}/kivyforge/cli/upgrade.py +96 -60
  31. {kivyforge-3.0.0.dev0 → kivyforge-3.0.0.dev1}/kivyforge/config/__init__.py +2 -1
  32. kivyforge-3.0.0.dev1/kivyforge/config/keys.py +301 -0
  33. {kivyforge-3.0.0.dev0 → kivyforge-3.0.0.dev1}/kivyforge/config/loader.py +558 -102
  34. {kivyforge-3.0.0.dev0 → kivyforge-3.0.0.dev1}/kivyforge/config/model.py +135 -17
  35. kivyforge-3.0.0.dev1/kivyforge/config/version.py +124 -0
  36. kivyforge-3.0.0.dev1/kivyforge/doctor/checks_common.py +229 -0
  37. {kivyforge-3.0.0.dev0 → kivyforge-3.0.0.dev1}/kivyforge/doctor/probe.py +52 -3
  38. kivyforge-3.0.0.dev1/kivyforge/doctor/result.py +71 -0
  39. kivyforge-3.0.0.dev1/kivyforge/host.py +29 -0
  40. {kivyforge-3.0.0.dev0 → kivyforge-3.0.0.dev1}/kivyforge/lock/find_links.py +24 -4
  41. {kivyforge-3.0.0.dev0 → kivyforge-3.0.0.dev1}/kivyforge/lock/reader.py +3 -1
  42. {kivyforge-3.0.0.dev0 → kivyforge-3.0.0.dev1}/kivyforge/lock/resolver.py +18 -0
  43. {kivyforge-3.0.0.dev0 → kivyforge-3.0.0.dev1}/kivyforge/lock/wheelruntime/builder.py +35 -5
  44. {kivyforge-3.0.0.dev0 → kivyforge-3.0.0.dev1}/kivyforge/lock/wheelruntime/pbs_github.py +58 -1
  45. {kivyforge-3.0.0.dev0 → kivyforge-3.0.0.dev1}/kivyforge/lock/wheelruntime/profile.py +1 -1
  46. {kivyforge-3.0.0.dev0 → kivyforge-3.0.0.dev1}/kivyforge/lock/wheelruntime/resolver.py +13 -4
  47. {kivyforge-3.0.0.dev0 → kivyforge-3.0.0.dev1}/kivyforge/lock/wheelruntime/serialize.py +1 -0
  48. kivyforge-3.0.0.dev1/kivyforge/net.py +21 -0
  49. kivyforge-3.0.0.dev1/kivyforge/platforms/android/__init__.py +252 -0
  50. {kivyforge-3.0.0.dev0 → kivyforge-3.0.0.dev1}/kivyforge/platforms/android/adb.py +76 -6
  51. {kivyforge-3.0.0.dev0 → kivyforge-3.0.0.dev1}/kivyforge/platforms/android/bootstrap/contract.py +68 -19
  52. {kivyforge-3.0.0.dev0 → kivyforge-3.0.0.dev1}/kivyforge/platforms/android/bootstrap/render.py +167 -14
  53. kivyforge-3.0.0.dev1/kivyforge/platforms/android/bootstrap/templates/android_pkg/__init__.py +81 -0
  54. kivyforge-3.0.0.dev1/kivyforge/platforms/android/bootstrap/templates/android_pkg/config.py +16 -0
  55. kivyforge-3.0.0.dev1/kivyforge/platforms/android/bootstrap/templates/android_pkg/loadingscreen.py +6 -0
  56. {kivyforge-3.0.0.dev0 → kivyforge-3.0.0.dev1}/kivyforge/platforms/android/bootstrap/templates/androidtest/KivyforgeContractTest.java +39 -3
  57. {kivyforge-3.0.0.dev0 → kivyforge-3.0.0.dev1}/kivyforge/platforms/android/bootstrap/templates/bootstrap_py/_kivyforge_selftest.py +64 -0
  58. {kivyforge-3.0.0.dev0 → kivyforge-3.0.0.dev1}/kivyforge/platforms/android/bootstrap/templates/cpp/main.c +12 -5
  59. kivyforge-3.0.0.dev1/kivyforge/platforms/android/bootstrap/templates/java/org/kivy/android/PythonActivity.java +319 -0
  60. {kivyforge-3.0.0.dev0 → kivyforge-3.0.0.dev1}/kivyforge/platforms/android/bootstrap/templates/java/org/kivy/android/PythonBundle.java +6 -3
  61. {kivyforge-3.0.0.dev0 → kivyforge-3.0.0.dev1}/kivyforge/platforms/android/bootstrap/templates/java/org/kivy/android/PythonService.java +89 -7
  62. {kivyforge-3.0.0.dev0 → kivyforge-3.0.0.dev1}/kivyforge/platforms/android/bootstrap/templates/java/org/renpy/android/Hardware.java +0 -21
  63. kivyforge-3.0.0.dev1/kivyforge/platforms/android/bootstrap/templates/p4a/LICENSE +21 -0
  64. kivyforge-3.0.0.dev1/kivyforge/platforms/android/bootstrap/templates/p4a/NOTICE +11 -0
  65. kivyforge-3.0.0.dev1/kivyforge/platforms/android/bootstrap/templates/p4a/P4A_VENDOR.toml +107 -0
  66. kivyforge-3.0.0.dev1/kivyforge/platforms/android/bootstrap/templates/p4a/android/activity.py +214 -0
  67. kivyforge-3.0.0.dev1/kivyforge/platforms/android/bootstrap/templates/p4a/android/broadcast.py +103 -0
  68. kivyforge-3.0.0.dev1/kivyforge/platforms/android/bootstrap/templates/p4a/android/darkmode.py +57 -0
  69. kivyforge-3.0.0.dev1/kivyforge/platforms/android/bootstrap/templates/p4a/android/permissions.py +621 -0
  70. kivyforge-3.0.0.dev1/kivyforge/platforms/android/bootstrap/templates/p4a/android/runnable.py +58 -0
  71. kivyforge-3.0.0.dev1/kivyforge/platforms/android/bootstrap/templates/p4a/android/storage.py +117 -0
  72. kivyforge-3.0.0.dev1/kivyforge/platforms/android/bootstrap/templates/p4a/java/PythonActivity.changeKeyboard.sdl3.java.in +9 -0
  73. kivyforge-3.0.0.dev1/kivyforge/platforms/android/bootstrap/templates/p4a/java/org/kivy/android/GenericBroadcastReceiver.java +19 -0
  74. kivyforge-3.0.0.dev1/kivyforge/platforms/android/bootstrap/templates/p4a/java/org/kivy/android/GenericBroadcastReceiverCallback.java +9 -0
  75. {kivyforge-3.0.0.dev0 → kivyforge-3.0.0.dev1}/kivyforge/platforms/android/bootstrap/templates/sdl2/org/libsdl/app/SDLActivity.java +5 -2
  76. kivyforge-3.0.0.dev1/kivyforge/platforms/android/cli.py +1617 -0
  77. {kivyforge-3.0.0.dev0 → kivyforge-3.0.0.dev1}/kivyforge/platforms/android/doctor.py +205 -37
  78. kivyforge-3.0.0.dev1/kivyforge/platforms/android/elf.py +267 -0
  79. {kivyforge-3.0.0.dev0 → kivyforge-3.0.0.dev1}/kivyforge/platforms/android/generate/manifest.py +103 -20
  80. {kivyforge-3.0.0.dev0 → kivyforge-3.0.0.dev1}/kivyforge/platforms/android/generate/project.py +81 -14
  81. {kivyforge-3.0.0.dev0 → kivyforge-3.0.0.dev1}/kivyforge/platforms/android/generate/services.py +56 -9
  82. kivyforge-3.0.0.dev1/kivyforge/platforms/android/gradlew.py +130 -0
  83. {kivyforge-3.0.0.dev0 → kivyforge-3.0.0.dev1}/kivyforge/platforms/android/icons.py +5 -19
  84. {kivyforge-3.0.0.dev0 → kivyforge-3.0.0.dev1}/kivyforge/platforms/android/lock/builder.py +143 -5
  85. kivyforge-3.0.0.dev1/kivyforge/platforms/android/lock/generation.py +39 -0
  86. {kivyforge-3.0.0.dev0 → kivyforge-3.0.0.dev1}/kivyforge/platforms/android/lock/maven.py +49 -7
  87. {kivyforge-3.0.0.dev0 → kivyforge-3.0.0.dev1}/kivyforge/platforms/android/lock/model.py +1 -0
  88. {kivyforge-3.0.0.dev0 → kivyforge-3.0.0.dev1}/kivyforge/platforms/android/lock/python_meta.py +30 -3
  89. {kivyforge-3.0.0.dev0 → kivyforge-3.0.0.dev1}/kivyforge/platforms/android/lock/reader.py +1 -0
  90. {kivyforge-3.0.0.dev0 → kivyforge-3.0.0.dev1}/kivyforge/platforms/android/lock/resolver.py +112 -8
  91. {kivyforge-3.0.0.dev0 → kivyforge-3.0.0.dev1}/kivyforge/platforms/android/lock/writer.py +2 -0
  92. kivyforge-3.0.0.dev1/kivyforge/platforms/android/sdk_packages.py +116 -0
  93. {kivyforge-3.0.0.dev0 → kivyforge-3.0.0.dev1}/kivyforge/platforms/android/signing.py +25 -15
  94. {kivyforge-3.0.0.dev0 → kivyforge-3.0.0.dev1}/kivyforge/platforms/android/splash.py +4 -17
  95. {kivyforge-3.0.0.dev0 → kivyforge-3.0.0.dev1}/kivyforge/platforms/android/stage/bundle.py +30 -7
  96. kivyforge-3.0.0.dev1/kivyforge/platforms/android/stage/conflicts.py +73 -0
  97. kivyforge-3.0.0.dev1/kivyforge/platforms/android/stage/jnilibs.py +332 -0
  98. kivyforge-3.0.0.dev1/kivyforge/platforms/android/stage/layouts.py +39 -0
  99. {kivyforge-3.0.0.dev0 → kivyforge-3.0.0.dev1}/kivyforge/platforms/android/stage/wheels.py +2 -1
  100. kivyforge-3.0.0.dev1/kivyforge/platforms/android/streaming.py +92 -0
  101. {kivyforge-3.0.0.dev0 → kivyforge-3.0.0.dev1}/kivyforge/platforms/android/toolchain.py +12 -0
  102. {kivyforge-3.0.0.dev0 → kivyforge-3.0.0.dev1}/kivyforge/platforms/base.py +34 -5
  103. {kivyforge-3.0.0.dev0 → kivyforge-3.0.0.dev1}/kivyforge/platforms/ios/__init__.py +39 -8
  104. kivyforge-3.0.0.dev1/kivyforge/platforms/ios/buildsettings.py +243 -0
  105. {kivyforge-3.0.0.dev0 → kivyforge-3.0.0.dev1}/kivyforge/platforms/ios/cli.py +252 -93
  106. {kivyforge-3.0.0.dev0 → kivyforge-3.0.0.dev1}/kivyforge/platforms/ios/doctor.py +211 -11
  107. kivyforge-3.0.0.dev1/kivyforge/platforms/ios/entitlements.py +282 -0
  108. {kivyforge-3.0.0.dev0 → kivyforge-3.0.0.dev1}/kivyforge/platforms/ios/generator.py +101 -5
  109. {kivyforge-3.0.0.dev0 → kivyforge-3.0.0.dev1}/kivyforge/platforms/ios/lock/builder.py +39 -7
  110. {kivyforge-3.0.0.dev0 → kivyforge-3.0.0.dev1}/kivyforge/platforms/ios/lock/python_meta.py +2 -1
  111. {kivyforge-3.0.0.dev0 → kivyforge-3.0.0.dev1}/kivyforge/platforms/ios/lock/resolver.py +23 -4
  112. {kivyforge-3.0.0.dev0 → kivyforge-3.0.0.dev1}/kivyforge/platforms/ios/lock/spm.py +3 -1
  113. {kivyforge-3.0.0.dev0 → kivyforge-3.0.0.dev1}/kivyforge/platforms/ios/materialize.py +2 -0
  114. {kivyforge-3.0.0.dev0 → kivyforge-3.0.0.dev1}/kivyforge/platforms/ios/plist.py +1 -1
  115. {kivyforge-3.0.0.dev0 → kivyforge-3.0.0.dev1}/kivyforge/platforms/ios/skeleton.py +0 -2
  116. {kivyforge-3.0.0.dev0 → kivyforge-3.0.0.dev1}/kivyforge/platforms/ios/sources.py +45 -2
  117. {kivyforge-3.0.0.dev0 → kivyforge-3.0.0.dev1}/kivyforge/platforms/ios/staging.py +68 -12
  118. {kivyforge-3.0.0.dev0 → kivyforge-3.0.0.dev1}/kivyforge/platforms/ios/templates/kivyforge_bootstrap.h +6 -2
  119. {kivyforge-3.0.0.dev0 → kivyforge-3.0.0.dev1}/kivyforge/platforms/ios/templates/kivyforge_bootstrap.m +78 -21
  120. kivyforge-3.0.0.dev1/kivyforge/platforms/ios/templates/kivyforge_native_modules.h.in +35 -0
  121. {kivyforge-3.0.0.dev0 → kivyforge-3.0.0.dev1}/kivyforge/platforms/ios/xcode/__init__.py +2 -0
  122. {kivyforge-3.0.0.dev0 → kivyforge-3.0.0.dev1}/kivyforge/platforms/ios/xcode/commands.py +35 -2
  123. {kivyforge-3.0.0.dev0 → kivyforge-3.0.0.dev1}/kivyforge/platforms/ios/xcode/runner.py +93 -19
  124. {kivyforge-3.0.0.dev0 → kivyforge-3.0.0.dev1}/kivyforge/platforms/linux/__init__.py +28 -8
  125. {kivyforge-3.0.0.dev0 → kivyforge-3.0.0.dev1}/kivyforge/platforms/linux/appimage.py +52 -8
  126. {kivyforge-3.0.0.dev0 → kivyforge-3.0.0.dev1}/kivyforge/platforms/linux/bundle.py +46 -16
  127. kivyforge-3.0.0.dev1/kivyforge/platforms/linux/cli.py +287 -0
  128. {kivyforge-3.0.0.dev0 → kivyforge-3.0.0.dev1}/kivyforge/platforms/linux/desktop.py +3 -1
  129. {kivyforge-3.0.0.dev0 → kivyforge-3.0.0.dev1}/kivyforge/platforms/linux/doctor.py +40 -0
  130. {kivyforge-3.0.0.dev0 → kivyforge-3.0.0.dev1}/kivyforge/platforms/linux/icons.py +5 -17
  131. {kivyforge-3.0.0.dev0 → kivyforge-3.0.0.dev1}/kivyforge/platforms/linux/launcher.py +44 -5
  132. {kivyforge-3.0.0.dev0 → kivyforge-3.0.0.dev1}/kivyforge/platforms/linux/lock/profile.py +2 -2
  133. {kivyforge-3.0.0.dev0 → kivyforge-3.0.0.dev1}/kivyforge/platforms/linux/lock/runtime.py +1 -0
  134. {kivyforge-3.0.0.dev0 → kivyforge-3.0.0.dev1}/kivyforge/platforms/linux/runtime_stage.py +23 -2
  135. {kivyforge-3.0.0.dev0 → kivyforge-3.0.0.dev1}/kivyforge/platforms/macos/__init__.py +28 -8
  136. {kivyforge-3.0.0.dev0 → kivyforge-3.0.0.dev1}/kivyforge/platforms/macos/bundle.py +47 -14
  137. {kivyforge-3.0.0.dev0 → kivyforge-3.0.0.dev1}/kivyforge/platforms/macos/cli.py +122 -71
  138. {kivyforge-3.0.0.dev0 → kivyforge-3.0.0.dev1}/kivyforge/platforms/macos/doctor.py +10 -0
  139. {kivyforge-3.0.0.dev0 → kivyforge-3.0.0.dev1}/kivyforge/platforms/macos/icns.py +14 -5
  140. {kivyforge-3.0.0.dev0 → kivyforge-3.0.0.dev1}/kivyforge/platforms/macos/launcher.py +59 -12
  141. {kivyforge-3.0.0.dev0 → kivyforge-3.0.0.dev1}/kivyforge/platforms/macos/machotools.py +66 -4
  142. {kivyforge-3.0.0.dev0 → kivyforge-3.0.0.dev1}/kivyforge/platforms/macos/notarize.py +12 -4
  143. {kivyforge-3.0.0.dev0 → kivyforge-3.0.0.dev1}/kivyforge/platforms/macos/plist.py +1 -1
  144. {kivyforge-3.0.0.dev0 → kivyforge-3.0.0.dev1}/kivyforge/platforms/macos/runtime_stage.py +22 -2
  145. {kivyforge-3.0.0.dev0 → kivyforge-3.0.0.dev1}/kivyforge/platforms/windows/__init__.py +28 -8
  146. {kivyforge-3.0.0.dev0 → kivyforge-3.0.0.dev1}/kivyforge/platforms/windows/bundle.py +48 -18
  147. {kivyforge-3.0.0.dev0 → kivyforge-3.0.0.dev1}/kivyforge/platforms/windows/cli.py +157 -69
  148. {kivyforge-3.0.0.dev0 → kivyforge-3.0.0.dev1}/kivyforge/platforms/windows/doctor.py +13 -1
  149. {kivyforge-3.0.0.dev0 → kivyforge-3.0.0.dev1}/kivyforge/platforms/windows/icons.py +7 -19
  150. kivyforge-3.0.0.dev1/kivyforge/platforms/windows/pathdepth.py +60 -0
  151. {kivyforge-3.0.0.dev0 → kivyforge-3.0.0.dev1}/kivyforge/platforms/windows/rcedit.py +7 -2
  152. {kivyforge-3.0.0.dev0 → kivyforge-3.0.0.dev1}/kivyforge/platforms/windows/runtime_stage.py +23 -2
  153. {kivyforge-3.0.0.dev0 → kivyforge-3.0.0.dev1}/kivyforge/platforms/windows/signing.py +7 -2
  154. {kivyforge-3.0.0.dev0 → kivyforge-3.0.0.dev1}/kivyforge/platforms/windows/vendor/SHA256SUMS +1 -1
  155. {kivyforge-3.0.0.dev0 → kivyforge-3.0.0.dev1}/kivyforge/platforms/windows/vendor/fetch_rcedit.py +3 -1
  156. {kivyforge-3.0.0.dev0 → kivyforge-3.0.0.dev1}/kivyforge/platforms/windows/vendor/launcher-amd64.exe +0 -0
  157. kivyforge-3.0.0.dev1/kivyforge/report/__init__.py +31 -0
  158. kivyforge-3.0.0.dev1/kivyforge/report/console.py +231 -0
  159. kivyforge-3.0.0.dev1/kivyforge/report/diagnostics.py +224 -0
  160. kivyforge-3.0.0.dev1/kivyforge/report/envelope.py +79 -0
  161. kivyforge-3.0.0.dev1/kivyforge/report/exit_codes.py +56 -0
  162. kivyforge-3.0.0.dev1/kivyforge/report/failures.py +123 -0
  163. kivyforge-3.0.0.dev1/kivyforge/report/streams.py +71 -0
  164. kivyforge-3.0.0.dev1/kivyforge/report/transfers.py +209 -0
  165. kivyforge-3.0.0.dev1/kivyforge/status.py +179 -0
  166. kivyforge-3.0.0.dev1/kivyforge/versioning.py +273 -0
  167. {kivyforge-3.0.0.dev0 → kivyforge-3.0.0.dev1/kivyforge.egg-info}/PKG-INFO +144 -36
  168. {kivyforge-3.0.0.dev0 → kivyforge-3.0.0.dev1}/kivyforge.egg-info/SOURCES.txt +45 -1
  169. {kivyforge-3.0.0.dev0 → kivyforge-3.0.0.dev1}/kivyforge.egg-info/requires.txt +6 -8
  170. {kivyforge-3.0.0.dev0 → kivyforge-3.0.0.dev1}/pyproject.toml +38 -19
  171. kivyforge-3.0.0.dev0/CHANGELOG.md +0 -670
  172. kivyforge-3.0.0.dev0/kivyforge/__init__.py +0 -9
  173. kivyforge-3.0.0.dev0/kivyforge/bundle/pycompile.py +0 -161
  174. kivyforge-3.0.0.dev0/kivyforge/cli/_common.py +0 -62
  175. kivyforge-3.0.0.dev0/kivyforge/cli/build.py +0 -111
  176. kivyforge-3.0.0.dev0/kivyforge/cli/clean.py +0 -135
  177. kivyforge-3.0.0.dev0/kivyforge/cli/doctor.py +0 -52
  178. kivyforge-3.0.0.dev0/kivyforge/cli/open_cmd.py +0 -15
  179. kivyforge-3.0.0.dev0/kivyforge/cli/status.py +0 -20
  180. kivyforge-3.0.0.dev0/kivyforge/doctor/checks_common.py +0 -95
  181. kivyforge-3.0.0.dev0/kivyforge/doctor/result.py +0 -41
  182. kivyforge-3.0.0.dev0/kivyforge/platforms/android/__init__.py +0 -140
  183. kivyforge-3.0.0.dev0/kivyforge/platforms/android/bootstrap/templates/java/org/kivy/android/PythonActivity.java +0 -75
  184. kivyforge-3.0.0.dev0/kivyforge/platforms/android/cli.py +0 -1023
  185. kivyforge-3.0.0.dev0/kivyforge/platforms/android/elf.py +0 -148
  186. kivyforge-3.0.0.dev0/kivyforge/platforms/android/gradlew.py +0 -60
  187. kivyforge-3.0.0.dev0/kivyforge/platforms/android/stage/jnilibs.py +0 -186
  188. kivyforge-3.0.0.dev0/kivyforge/platforms/ios/buildsettings.py +0 -128
  189. kivyforge-3.0.0.dev0/kivyforge/platforms/ios/entitlements.py +0 -34
  190. kivyforge-3.0.0.dev0/kivyforge/platforms/linux/cli.py +0 -232
  191. {kivyforge-3.0.0.dev0 → kivyforge-3.0.0.dev1}/LICENSE +0 -0
  192. {kivyforge-3.0.0.dev0 → kivyforge-3.0.0.dev1}/MANIFEST.in +0 -0
  193. {kivyforge-3.0.0.dev0 → kivyforge-3.0.0.dev1}/kivyforge/artifacts/__init__.py +0 -0
  194. {kivyforge-3.0.0.dev0 → kivyforge-3.0.0.dev1}/kivyforge/artifacts/cache.py +0 -0
  195. {kivyforge-3.0.0.dev0 → kivyforge-3.0.0.dev1}/kivyforge/artifacts/frameworks.py +0 -0
  196. {kivyforge-3.0.0.dev0 → kivyforge-3.0.0.dev1}/kivyforge/artifacts/native_stage_util.py +0 -0
  197. {kivyforge-3.0.0.dev0 → kivyforge-3.0.0.dev1}/kivyforge/artifacts/runtime.py +0 -0
  198. {kivyforge-3.0.0.dev0 → kivyforge-3.0.0.dev1}/kivyforge/artifacts/verify.py +0 -0
  199. {kivyforge-3.0.0.dev0 → kivyforge-3.0.0.dev1}/kivyforge/bundle/__init__.py +0 -0
  200. {kivyforge-3.0.0.dev0 → kivyforge-3.0.0.dev1}/kivyforge/config/errors.py +0 -0
  201. {kivyforge-3.0.0.dev0 → kivyforge-3.0.0.dev1}/kivyforge/config/icons.py +0 -0
  202. {kivyforge-3.0.0.dev0 → kivyforge-3.0.0.dev1}/kivyforge/doctor/__init__.py +0 -0
  203. {kivyforge-3.0.0.dev0 → kivyforge-3.0.0.dev1}/kivyforge/lock/__init__.py +0 -0
  204. {kivyforge-3.0.0.dev0 → kivyforge-3.0.0.dev1}/kivyforge/lock/_pip_shim.py +0 -0
  205. {kivyforge-3.0.0.dev0 → kivyforge-3.0.0.dev1}/kivyforge/lock/model.py +0 -0
  206. {kivyforge-3.0.0.dev0 → kivyforge-3.0.0.dev1}/kivyforge/lock/pep751.py +0 -0
  207. {kivyforge-3.0.0.dev0 → kivyforge-3.0.0.dev1}/kivyforge/lock/wheelruntime/__init__.py +0 -0
  208. {kivyforge-3.0.0.dev0 → kivyforge-3.0.0.dev1}/kivyforge/lock/wheelruntime/model.py +0 -0
  209. {kivyforge-3.0.0.dev0 → kivyforge-3.0.0.dev1}/kivyforge/lock/wheelruntime/native_binaries.py +0 -0
  210. {kivyforge-3.0.0.dev0 → kivyforge-3.0.0.dev1}/kivyforge/lock/wheelruntime/runtime.py +0 -0
  211. {kivyforge-3.0.0.dev0 → kivyforge-3.0.0.dev1}/kivyforge/platforms/__init__.py +0 -0
  212. {kivyforge-3.0.0.dev0 → kivyforge-3.0.0.dev1}/kivyforge/platforms/android/bootstrap/__init__.py +0 -0
  213. {kivyforge-3.0.0.dev0 → kivyforge-3.0.0.dev1}/kivyforge/platforms/android/bootstrap/templates/bootstrap_py/_kivy_bootstrap.py +0 -0
  214. {kivyforge-3.0.0.dev0 → kivyforge-3.0.0.dev1}/kivyforge/platforms/android/bootstrap/templates/bootstrap_py/_kivyforge_bootstrap.py +0 -0
  215. {kivyforge-3.0.0.dev0 → kivyforge-3.0.0.dev1}/kivyforge/platforms/android/bootstrap/templates/cpp/CMakeLists.txt +0 -0
  216. {kivyforge-3.0.0.dev0 → kivyforge-3.0.0.dev1}/kivyforge/platforms/android/bootstrap/templates/java/org/jnius/NativeInvocationHandler.java +0 -0
  217. {kivyforge-3.0.0.dev0 → kivyforge-3.0.0.dev1}/kivyforge/platforms/android/bootstrap/templates/sdl2/LICENSE-SDL.txt +0 -0
  218. {kivyforge-3.0.0.dev0 → kivyforge-3.0.0.dev1}/kivyforge/platforms/android/bootstrap/templates/sdl2/SDL_REVISION.txt +0 -0
  219. {kivyforge-3.0.0.dev0 → kivyforge-3.0.0.dev1}/kivyforge/platforms/android/bootstrap/templates/sdl2/org/libsdl/app/HIDDevice.java +0 -0
  220. {kivyforge-3.0.0.dev0 → kivyforge-3.0.0.dev1}/kivyforge/platforms/android/bootstrap/templates/sdl2/org/libsdl/app/HIDDeviceBLESteamController.java +0 -0
  221. {kivyforge-3.0.0.dev0 → kivyforge-3.0.0.dev1}/kivyforge/platforms/android/bootstrap/templates/sdl2/org/libsdl/app/HIDDeviceManager.java +0 -0
  222. {kivyforge-3.0.0.dev0 → kivyforge-3.0.0.dev1}/kivyforge/platforms/android/bootstrap/templates/sdl2/org/libsdl/app/HIDDeviceUSB.java +0 -0
  223. {kivyforge-3.0.0.dev0 → kivyforge-3.0.0.dev1}/kivyforge/platforms/android/bootstrap/templates/sdl2/org/libsdl/app/SDL.java +0 -0
  224. {kivyforge-3.0.0.dev0 → kivyforge-3.0.0.dev1}/kivyforge/platforms/android/bootstrap/templates/sdl2/org/libsdl/app/SDLAudioManager.java +0 -0
  225. {kivyforge-3.0.0.dev0 → kivyforge-3.0.0.dev1}/kivyforge/platforms/android/bootstrap/templates/sdl2/org/libsdl/app/SDLControllerManager.java +0 -0
  226. {kivyforge-3.0.0.dev0 → kivyforge-3.0.0.dev1}/kivyforge/platforms/android/bootstrap/templates/sdl2/org/libsdl/app/SDLSurface.java +0 -0
  227. {kivyforge-3.0.0.dev0 → kivyforge-3.0.0.dev1}/kivyforge/platforms/android/bootstrap/templates/sdl3/LICENSE-SDL.txt +0 -0
  228. {kivyforge-3.0.0.dev0 → kivyforge-3.0.0.dev1}/kivyforge/platforms/android/bootstrap/templates/sdl3/SDL_REVISION.txt +0 -0
  229. {kivyforge-3.0.0.dev0 → kivyforge-3.0.0.dev1}/kivyforge/platforms/android/bootstrap/templates/sdl3/org/libsdl/app/HIDDevice.java +0 -0
  230. {kivyforge-3.0.0.dev0 → kivyforge-3.0.0.dev1}/kivyforge/platforms/android/bootstrap/templates/sdl3/org/libsdl/app/HIDDeviceBLESteamController.java +0 -0
  231. {kivyforge-3.0.0.dev0 → kivyforge-3.0.0.dev1}/kivyforge/platforms/android/bootstrap/templates/sdl3/org/libsdl/app/HIDDeviceManager.java +0 -0
  232. {kivyforge-3.0.0.dev0 → kivyforge-3.0.0.dev1}/kivyforge/platforms/android/bootstrap/templates/sdl3/org/libsdl/app/HIDDeviceUSB.java +0 -0
  233. {kivyforge-3.0.0.dev0 → kivyforge-3.0.0.dev1}/kivyforge/platforms/android/bootstrap/templates/sdl3/org/libsdl/app/SDL.java +0 -0
  234. {kivyforge-3.0.0.dev0 → kivyforge-3.0.0.dev1}/kivyforge/platforms/android/bootstrap/templates/sdl3/org/libsdl/app/SDLActivity.java +0 -0
  235. {kivyforge-3.0.0.dev0 → kivyforge-3.0.0.dev1}/kivyforge/platforms/android/bootstrap/templates/sdl3/org/libsdl/app/SDLAudioManager.java +0 -0
  236. {kivyforge-3.0.0.dev0 → kivyforge-3.0.0.dev1}/kivyforge/platforms/android/bootstrap/templates/sdl3/org/libsdl/app/SDLControllerManager.java +0 -0
  237. {kivyforge-3.0.0.dev0 → kivyforge-3.0.0.dev1}/kivyforge/platforms/android/bootstrap/templates/sdl3/org/libsdl/app/SDLDummyEdit.java +0 -0
  238. {kivyforge-3.0.0.dev0 → kivyforge-3.0.0.dev1}/kivyforge/platforms/android/bootstrap/templates/sdl3/org/libsdl/app/SDLInputConnection.java +0 -0
  239. {kivyforge-3.0.0.dev0 → kivyforge-3.0.0.dev1}/kivyforge/platforms/android/bootstrap/templates/sdl3/org/libsdl/app/SDLSensorManager.java +0 -0
  240. {kivyforge-3.0.0.dev0 → kivyforge-3.0.0.dev1}/kivyforge/platforms/android/bootstrap/templates/sdl3/org/libsdl/app/SDLSurface.java +0 -0
  241. {kivyforge-3.0.0.dev0 → kivyforge-3.0.0.dev1}/kivyforge/platforms/android/generate/__init__.py +0 -0
  242. {kivyforge-3.0.0.dev0 → kivyforge-3.0.0.dev1}/kivyforge/platforms/android/gradle_wrapper/NOTICE +0 -0
  243. {kivyforge-3.0.0.dev0 → kivyforge-3.0.0.dev1}/kivyforge/platforms/android/gradle_wrapper/SHA256SUMS +0 -0
  244. {kivyforge-3.0.0.dev0 → kivyforge-3.0.0.dev1}/kivyforge/platforms/android/gradle_wrapper/gradle-wrapper.jar +0 -0
  245. {kivyforge-3.0.0.dev0 → kivyforge-3.0.0.dev1}/kivyforge/platforms/android/gradle_wrapper/gradlew +0 -0
  246. {kivyforge-3.0.0.dev0 → kivyforge-3.0.0.dev1}/kivyforge/platforms/android/gradle_wrapper/gradlew.bat +0 -0
  247. {kivyforge-3.0.0.dev0 → kivyforge-3.0.0.dev1}/kivyforge/platforms/android/lock/__init__.py +0 -0
  248. {kivyforge-3.0.0.dev0 → kivyforge-3.0.0.dev1}/kivyforge/platforms/android/lock/archives.py +0 -0
  249. {kivyforge-3.0.0.dev0 → kivyforge-3.0.0.dev1}/kivyforge/platforms/android/lock/markers.py +0 -0
  250. {kivyforge-3.0.0.dev0 → kivyforge-3.0.0.dev1}/kivyforge/platforms/android/policy.py +0 -0
  251. {kivyforge-3.0.0.dev0 → kivyforge-3.0.0.dev1}/kivyforge/platforms/android/smoke.py +0 -0
  252. {kivyforge-3.0.0.dev0 → kivyforge-3.0.0.dev1}/kivyforge/platforms/android/stage/__init__.py +0 -0
  253. {kivyforge-3.0.0.dev0 → kivyforge-3.0.0.dev1}/kivyforge/platforms/android/stage/runtime.py +0 -0
  254. {kivyforge-3.0.0.dev0 → kivyforge-3.0.0.dev1}/kivyforge/platforms/ios/assets.py +0 -0
  255. {kivyforge-3.0.0.dev0 → kivyforge-3.0.0.dev1}/kivyforge/platforms/ios/lock/__init__.py +0 -0
  256. {kivyforge-3.0.0.dev0 → kivyforge-3.0.0.dev1}/kivyforge/platforms/ios/lock/markers.py +0 -0
  257. {kivyforge-3.0.0.dev0 → kivyforge-3.0.0.dev1}/kivyforge/platforms/ios/lock/model.py +0 -0
  258. {kivyforge-3.0.0.dev0 → kivyforge-3.0.0.dev1}/kivyforge/platforms/ios/lock/reader.py +0 -0
  259. {kivyforge-3.0.0.dev0 → kivyforge-3.0.0.dev1}/kivyforge/platforms/ios/lock/writer.py +0 -0
  260. {kivyforge-3.0.0.dev0 → kivyforge-3.0.0.dev1}/kivyforge/platforms/ios/lock/xcframework.py +0 -0
  261. {kivyforge-3.0.0.dev0 → kivyforge-3.0.0.dev1}/kivyforge/platforms/ios/privacy.py +0 -0
  262. {kivyforge-3.0.0.dev0 → kivyforge-3.0.0.dev1}/kivyforge/platforms/ios/swift_packages.py +0 -0
  263. {kivyforge-3.0.0.dev0 → kivyforge-3.0.0.dev1}/kivyforge/platforms/ios/templates/main.m +0 -0
  264. {kivyforge-3.0.0.dev0 → kivyforge-3.0.0.dev1}/kivyforge/platforms/ios/templates/main_config.h.in +0 -0
  265. {kivyforge-3.0.0.dev0 → kivyforge-3.0.0.dev1}/kivyforge/platforms/ios/xcframeworks.py +0 -0
  266. {kivyforge-3.0.0.dev0 → kivyforge-3.0.0.dev1}/kivyforge/platforms/linux/elftools.py +0 -0
  267. {kivyforge-3.0.0.dev0 → kivyforge-3.0.0.dev1}/kivyforge/platforms/linux/lock/__init__.py +0 -0
  268. {kivyforge-3.0.0.dev0 → kivyforge-3.0.0.dev1}/kivyforge/platforms/linux/native_stage.py +0 -0
  269. {kivyforge-3.0.0.dev0 → kivyforge-3.0.0.dev1}/kivyforge/platforms/linux/wheels_stage.py +0 -0
  270. {kivyforge-3.0.0.dev0 → kivyforge-3.0.0.dev1}/kivyforge/platforms/macos/lock/__init__.py +0 -0
  271. {kivyforge-3.0.0.dev0 → kivyforge-3.0.0.dev1}/kivyforge/platforms/macos/lock/profile.py +0 -0
  272. {kivyforge-3.0.0.dev0 → kivyforge-3.0.0.dev1}/kivyforge/platforms/macos/lock/runtime.py +0 -0
  273. {kivyforge-3.0.0.dev0 → kivyforge-3.0.0.dev1}/kivyforge/platforms/macos/native_stage.py +0 -0
  274. {kivyforge-3.0.0.dev0 → kivyforge-3.0.0.dev1}/kivyforge/platforms/macos/signing.py +0 -0
  275. {kivyforge-3.0.0.dev0 → kivyforge-3.0.0.dev1}/kivyforge/platforms/macos/wheels_stage.py +0 -0
  276. {kivyforge-3.0.0.dev0 → kivyforge-3.0.0.dev1}/kivyforge/platforms/windows/assets.py +0 -0
  277. {kivyforge-3.0.0.dev0 → kivyforge-3.0.0.dev1}/kivyforge/platforms/windows/fsswap.py +0 -0
  278. {kivyforge-3.0.0.dev0 → kivyforge-3.0.0.dev1}/kivyforge/platforms/windows/launcher/__init__.py +0 -0
  279. {kivyforge-3.0.0.dev0 → kivyforge-3.0.0.dev1}/kivyforge/platforms/windows/launcher/build_launcher.py +0 -0
  280. {kivyforge-3.0.0.dev0 → kivyforge-3.0.0.dev1}/kivyforge/platforms/windows/launcher/launcher.c +0 -0
  281. {kivyforge-3.0.0.dev0 → kivyforge-3.0.0.dev1}/kivyforge/platforms/windows/lock/__init__.py +0 -0
  282. {kivyforge-3.0.0.dev0 → kivyforge-3.0.0.dev1}/kivyforge/platforms/windows/lock/profile.py +0 -0
  283. {kivyforge-3.0.0.dev0 → kivyforge-3.0.0.dev1}/kivyforge/platforms/windows/lock/runtime.py +0 -0
  284. {kivyforge-3.0.0.dev0 → kivyforge-3.0.0.dev1}/kivyforge/platforms/windows/naming.py +0 -0
  285. {kivyforge-3.0.0.dev0 → kivyforge-3.0.0.dev1}/kivyforge/platforms/windows/native_stage.py +0 -0
  286. {kivyforge-3.0.0.dev0 → kivyforge-3.0.0.dev1}/kivyforge/platforms/windows/petools.py +0 -0
  287. {kivyforge-3.0.0.dev0 → kivyforge-3.0.0.dev1}/kivyforge/platforms/windows/vendor/LICENSE.rcedit +0 -0
  288. {kivyforge-3.0.0.dev0 → kivyforge-3.0.0.dev1}/kivyforge/platforms/windows/vendor/NOTICE +0 -0
  289. {kivyforge-3.0.0.dev0 → kivyforge-3.0.0.dev1}/kivyforge/platforms/windows/vendor/TOOLSET.txt +0 -0
  290. {kivyforge-3.0.0.dev0 → kivyforge-3.0.0.dev1}/kivyforge/platforms/windows/vendor/__init__.py +0 -0
  291. {kivyforge-3.0.0.dev0 → kivyforge-3.0.0.dev1}/kivyforge/platforms/windows/vendor/rcedit-x64.exe +0 -0
  292. {kivyforge-3.0.0.dev0 → kivyforge-3.0.0.dev1}/kivyforge/platforms/windows/wheels_stage.py +0 -0
  293. {kivyforge-3.0.0.dev0 → kivyforge-3.0.0.dev1}/kivyforge.egg-info/dependency_links.txt +0 -0
  294. {kivyforge-3.0.0.dev0 → kivyforge-3.0.0.dev1}/kivyforge.egg-info/entry_points.txt +0 -0
  295. {kivyforge-3.0.0.dev0 → kivyforge-3.0.0.dev1}/kivyforge.egg-info/top_level.txt +0 -0
  296. {kivyforge-3.0.0.dev0 → kivyforge-3.0.0.dev1}/setup.cfg +0 -0
@@ -0,0 +1,1944 @@
1
+ # Changelog
2
+
3
+ ## [Unreleased]
4
+
5
+ ## [v3.0.0.dev1](https://github.com/ElliotGarbus/kivyforge/tree/v3.0.0.dev1) - 2026-10-14
6
+
7
+ ### All platforms: the app's own package metadata
8
+
9
+ - **Added:** kivyforge writes each app's package metadata into the app, from
10
+ `[project]` ([#122](https://github.com/ElliotGarbus/kivyforge/issues/122)):
11
+ a `<name>-<version>.dist-info` folder beside the app's code on macOS, Linux,
12
+ Windows, Android and iOS. Inside the app, `importlib.metadata` now finds the
13
+ app's name, its version (the same value as `versionName` and
14
+ `CFBundleShortVersionString`), the entry points of `[project.scripts]`,
15
+ `[project.gui-scripts]` and `[project.entry-points]`, and its modules
16
+ through `packages_distributions()`, for every build backend and layout, with
17
+ or without a development install. Before, an app had metadata only if a
18
+ setuptools dev install had left an `egg-info` in `app_dir`, as old as that
19
+ install. See
20
+ [Read your package metadata inside the app](docs/guides/guides/cross-platform/versioning.md#read-your-package-metadata-inside-the-app).
21
+ - **Changed:** a development `*.egg-info` folder at the top of `app_dir`, and a
22
+ `.dist-info` folder of the app's own name there, no longer ship in the app;
23
+ the generated folder replaces them. Your source tree is not changed. On iOS,
24
+ `kivyforge build` stages the folder in `<app>-ios/_kivyforge_meta/` and the
25
+ generated Build Python script copies it into the bundle, so Xcode-only
26
+ rebuilds keep it. **Migration:** an app that read its metadata from the
27
+ `egg-info` now reads the same names from the generated folder, current with
28
+ the build; nothing to change. An app whose code looks for the `egg-info`
29
+ folder itself should use `importlib.metadata` instead.
30
+ - **Changed:** a setuptools project that declares entry points only in
31
+ `setup.cfg` (`[options.entry_points]`) or `setup.py` (`entry_points=`), and
32
+ none in `[project]`, fails `build`, `package` and `run` with
33
+ `KF-METADATA-ENTRY-POINTS-OUTSIDE-PROJECT` (exit 1). kivyforge writes the
34
+ metadata from `[project]`, so the app would otherwise start without them.
35
+ **Migration:** move them into `[project.entry-points]`, console scripts into
36
+ `[project.scripts]` and GUI scripts into `[project.gui-scripts]`. setuptools
37
+ has deprecated reading them from those files for a project with a
38
+ `[project]` table.
39
+ - **Changed:** `[project]` entry points and `[project].name` are checked as
40
+ build backends check them, and each violation is a config error at its line
41
+ in every verb: a `console_scripts` or `gui_scripts` group under
42
+ `[project.entry-points]`, a nested table (usually a dotted group name left
43
+ unquoted), an invalid group name, an entry point name with `=` or a leading
44
+ `[` or whitespace, and a project name that is not valid. **Migration:** pip
45
+ could not have built such a project either; fix the table the message names.
46
+ - **Added:** when `[project].dynamic` lists `entry-points`, `scripts` or
47
+ `gui-scripts`, kivyforge cannot know the entry points, so it generates
48
+ nothing, leaves `app_dir` as it is, and warns with
49
+ `KF-METADATA-NOT-GENERATED`. Its `context` names the `reason` and the
50
+ development `egg-info` that ships instead (`fallback`).
51
+ - **Added:** Android's contract self-test, run by `run --smoke`, checks that
52
+ the app finds the metadata kivyforge generated.
53
+
54
+ ### iOS: rebuilding in Xcode keeps a device build signed
55
+
56
+ - **Fixed:** rebuilding a device build in Xcode (Cmd-B or Cmd-R, or re-running
57
+ the `xcodebuild` command kivyforge ran) succeeded but left the `.app` with an
58
+ invalid signature: `codesign --verify --deep --strict` reported "a sealed
59
+ resource is missing or invalid" and named every
60
+ `Frameworks/<module>.framework` binary. The Build Python script re-signs
61
+ those frameworks on every run, and with a real signing identity that changes
62
+ their bytes. Xcode didn't know the script writes into the bundle, so it
63
+ didn't sign the app again, and the app's signature still described the old
64
+ bytes. The script now declares what it writes (`python/`, `pip-deps/` and
65
+ `Frameworks/`) as its outputs, and Xcode signs the app again after it. That
66
+ adds about a second to an incremental build. The app from such a build still
67
+ installed and ran on iOS 27, but anything that checks its signature rejects
68
+ it. Simulator builds, signed ad hoc, stayed valid. A project generated by an
69
+ earlier kivyforge gets the fix at its next `kivyforge build`, which
70
+ regenerates the script phase.
71
+
72
+ ### iOS: the default deployment target is 16.0
73
+
74
+ - **Fixed:** with Xcode 27, `kivyforge build -p ios` failed for any project
75
+ that did not set `[tool.kivy.ios].deployment_target`. The default was 13.0,
76
+ and Xcode 27 accepts only 15.0 to 27.0.x, so xcodebuild stopped at the end
77
+ of the build ("The iOS deployment target 'IPHONEOS_DEPLOYMENT_TARGET' is set
78
+ to 13.0, but the range of supported deployment target versions is 15.0 to
79
+ 27.0.x"; `KF-BUILD-TOOL-FAILED`, exit 5). The default is now 16.0, not
80
+ Xcode's 15.0, because that is the oldest iOS Kivy's own iOS wheels run on:
81
+ their extension modules are built for iOS 16.0, so a lower target lets older
82
+ devices install an app that cannot load Kivy. `kivyforge init` writes 16.0,
83
+ and the `hello-world` example, the one example still at 13.0, now uses 16.0.
84
+ - **Fixed:** the generated Xcode project always had 13.0 as its project-level
85
+ `IPHONEOS_DEPLOYMENT_TARGET`, whatever `deployment_target` said. Only the app
86
+ target had the configured value. Both levels now use it, and the next build
87
+ of an existing `<app>-ios/` project corrects the old value.
88
+ - **Added:** `kivyforge doctor -p ios` has a "Deployment target" check. It reads
89
+ the range the selected Xcode accepts from the iOS SDK and fails when
90
+ `deployment_target` is outside it, before a build gets that far. Without a
91
+ project, it reports the range.
92
+ - **Migration:** what to do depends on how your project sets the key.
93
+ - **Set below 15.0:** Xcode 27 refuses the value whatever kivyforge's
94
+ default, so raise it (to `"16.0"` for a Kivy app). Any edit to
95
+ `pyproject.toml` makes `build` stop with `KF-LOCK-DRIFT` (exit 4), so run
96
+ `kivyforge lock -p ios` after the edit.
97
+ - **Not set:** you need no edit, but your app's minimum iOS rises from 13.0
98
+ to 16.0 (`MinimumOSVersion` and `IPHONEOS_DEPLOYMENT_TARGET`), so devices
99
+ below iOS 16 cannot install new builds. If your dependencies run on iOS 15
100
+ (Kivy's do not), set `deployment_target = "15.0"`, the lowest value
101
+ Xcode 27 accepts.
102
+ - **Existing locks stay valid.** The lock checks a hash of the text of
103
+ `pyproject.toml`, and a default is not in that text, so `build`,
104
+ `package` and `lock --check` accept a lock made before this change. A
105
+ re-lock does ask pip for `ios_16_0_*` tags instead of `ios_13_0_*`. Wheels
106
+ built for an older iOS still match, so the kivy and pyobjus wheels (tagged
107
+ `ios_13_0`) resolve to the same files. A package that publishes wheels for
108
+ several minimum iOS versions may resolve to a different file, which makes
109
+ `lock --check` report the lock as stale; run
110
+ `kivyforge lock -p ios --update`.
111
+
112
+ ### Guides
113
+
114
+ - **Added:** [Manage dependencies and re-lock](docs/guides/guides/cross-platform/dependencies.md)
115
+ explains how to pin a package with an exact specifier
116
+ ([#107](https://github.com/ElliotGarbus/kivyforge/issues/107)). A re-lock,
117
+ including one forced by an unrelated edit to `pyproject.toml`, resolves every
118
+ specifier to its newest match. `lock --check` does that resolve even when the
119
+ file hash still matches, so a range fails the check when a newer release
120
+ appears. `build` and `package` keep accepting that lock until the hash
121
+ changes.
122
+ - **Fixed:** [Install kivyforge](docs/guides/get-started/install.md) now
123
+ explains that every release so far is a pre-release, and its pipx and pip
124
+ commands carry the pre-release flag. Without it, both fail to find kivyforge.
125
+
126
+ ### Android
127
+
128
+ - **Added:** `kivyforge lock -p android` shows a progress bar while it
129
+ downloads the python.org CPython runtime, one per ABI, the first time that
130
+ tarball is not already cached ([#84](https://github.com/ElliotGarbus/kivyforge/issues/84)).
131
+ Before, that download printed nothing, so a first lock looked stuck until
132
+ `[lock] <abi>: resolving wheels`.
133
+ - **Changed:** `kivyforge build -p android` without `--debug` now ends with a
134
+ line saying Gradle did not run and naming the commands that produce an APK
135
+ ([#106](https://github.com/ElliotGarbus/kivyforge/issues/106)). Before, it
136
+ ended on `Generated <app>-android` with exit 0 and no APK, which read like a
137
+ successful build. What a bare build does is unchanged: it generates the
138
+ project and stages the release payload for `package`. If you run
139
+ `./gradlew assembleDebug` yourself on that project, the debug APK you get
140
+ contains the release payload. Use `build --debug` instead. `--json` output
141
+ is unchanged.
142
+
143
+ ### All platforms: dynamic versions
144
+
145
+ - **Added:** `dynamic = ["version"]` in `[project]` is supported
146
+ ([#111](https://github.com/ElliotGarbus/kivyforge/issues/111)). A project
147
+ that takes its version from git through setuptools-scm, hatch-vcs or another
148
+ build backend plugin no longer fails with "missing or empty
149
+ [project].version". `build`, `package` and `run` ask pip to prepare the
150
+ project's metadata, in an isolated environment, and print the version they
151
+ got. This works whether kivyforge was installed with `uv tool`, pipx or as a
152
+ project dependency. `lock`, `doctor`, `status` and `clean` never run pip, and
153
+ a new commit doesn't make the lock out of date. The first build needs the
154
+ network to fetch the backend. See
155
+ [Set the app version](docs/guides/guides/cross-platform/versioning.md).
156
+ - **Added:** `--app-version VERSION` on `build`, `package` and `run`, and the
157
+ `KIVYFORGE_APP_VERSION` environment variable (the flag wins), to set the
158
+ version without running the build backend. `--no-build-isolation` resolves a
159
+ dynamic version with a backend installed alongside kivyforge, offline.
160
+ - **Added:** `--json` envelopes from `build` and `package` carry
161
+ `data.version`: `{"value", "source"}`, where `source` is `override`, `static`
162
+ or `backend`. It is recorded before the build starts, so failed builds keep
163
+ it.
164
+ - **Added:** `doctor` reports a Version check. New codes:
165
+ `KF-VERSION-UNRESOLVED` (exit 1), `KF-VERSION-APPLE-FORMAT`,
166
+ `KF-VERSION-FILE-NOT-REFRESHED`, `KF-VERSION-ISOLATION-UNUSED`.
167
+ - **Changed:** an iOS export for the App Store (`package -p ios`, or
168
+ `build -p ios --release`, both with the default `--export-method app-store`)
169
+ fails before Xcode runs when the version isn't one to three dot-separated
170
+ numbers, such as `1.0rc1` or `1.2.3.4`. App Store Connect refuses such a
171
+ version at upload (ITMS-90060). Other iOS exports and macOS `package` warn
172
+ instead, and debug builds are unaffected. **Migration:** a static
173
+ pre-release version used to fail at upload; it now fails at `package`. Build
174
+ from a release version, pass `--app-version`, or export with
175
+ `--export-method ad-hoc` or `development`.
176
+ - **Changed:** `[project].version` must follow PEP 440, and kivyforge writes
177
+ its normalized form. **Migration:** `v1.2` becomes `1.2` in `versionName`,
178
+ the plists and file names; `1.0-beta` becomes `1.0b0`; a local segment is
179
+ lowercased with `-` turned into `.` (`1.0+Build-5` becomes `1.0+build.5`). A
180
+ version PEP 440 can't parse, such as `1.0.0-SNAPSHOT`, now fails to load;
181
+ pip already refused to build such a project.
182
+ - **Changed:** a `+` in the version becomes `_` in Linux `.AppImage` and
183
+ Windows `dist` folder names, since `+` turns into a space in URL query
184
+ strings. **Migration:** `1.0+local` now packages as `...-1.0_local-...`.
185
+ - **Changed:** listing `name`, `dependencies`, `authors`, `description` or
186
+ `requires-python` in `[project].dynamic` is now an error. kivyforge reads
187
+ those fields itself, and a dynamic one used to load as absent: a
188
+ `dynamic = ["dependencies"]` project locked no dependencies at all.
189
+ **Migration:** set the field statically.
190
+
191
+ ### Android: pyjnius versions
192
+
193
+ - **Fixed:** pyjnius 1.9.0 failed every Android build with "locked pyjnius 1.9.0
194
+ is outside the bootstrap template's compatible range"
195
+ ([#113](https://github.com/ElliotGarbus/kivyforge/issues/113)), though its
196
+ `invoke0` method is unchanged. kivyforge no longer caps the pyjnius version.
197
+ Instead of guessing from the version number, `build` now checks the installed
198
+ pyjnius wheel for the `invoke0` signature kivyforge's Java glue declares, and
199
+ fails with a message naming the wheel if it differs. New pyjnius releases that
200
+ keep the signature work without a kivyforge update.
201
+ - **Changed:** `kivyforge lock -p android` adds `pyjnius>=1.7.0` instead of
202
+ `pyjnius>=1.7.0,<1.9` when your project doesn't declare it, so a re-lock picks
203
+ the newest release. Existing locks need no change: a lock that already holds
204
+ pyjnius 1.9.0 now builds. Older than 1.7 still fails, and `doctor` only
205
+ checks that floor, since the wheel check needs the installed wheel.
206
+
207
+ ### Android: wheels built by cibuildwheel
208
+
209
+ - **Fixed:** numpy, pandas, matplotlib, opencv-python and other wheels that
210
+ cibuildwheel's default repair (auditwheel) produces failed to import on the
211
+ device with `dlopen failed: library "libc++_shared-d523468d.so" not found`.
212
+ These wheels carry their shared libraries in a top-level `<dist>.libs/`
213
+ directory (`numpy.libs/`), which kivyforge staged as Python extension modules
214
+ under new names. They are now staged under their own names, like the Kivy
215
+ wheel's `.libs/`.
216
+ - **Fixed:** once staged, the same libraries were corrupted by the strip during
217
+ packaging, and numpy then failed with errors like `cannot find "operty_get"
218
+ from verneed[0]`. patchelf, which auditwheel uses, lays these libraries out in
219
+ a way the NDK's `llvm-strip` mishandles. kivyforge now recognises them and
220
+ keeps their symbols, and the build says how many it kept.
221
+ - **Added:** after Gradle builds an APK or AAB, kivyforge checks every native
222
+ library in it and fails with `KF-ANDROID-NATIVE-LIB-MISALIGNED` if one could
223
+ not be loaded on a device, instead of shipping an app that crashes at import.
224
+ - **Changed:** debug builds no longer strip native libraries. The default
225
+ `strip_native_libs = "release"` was meant to keep symbols in debug builds, as
226
+ documented, but the generated project stripped both. Debug APKs grow by the
227
+ size of the symbols; set `strip_native_libs = true` to strip debug builds as
228
+ before.
229
+ - **Changed:** a wheel whose libraries directory holds a `.so` not named
230
+ `lib*.so` (for example `libgfortran-040039e1.so.5`) now fails the build with a
231
+ message naming the file. Android only packages `lib*.so` files, so before this
232
+ change the library was missing from the app.
233
+ - **Changed:** wheels from Flet's index (and others using Chaquopy's separate
234
+ library wheels, such as `flet-libjpeg`) now fail the build with
235
+ `KF-ANDROID-WHEEL-LAYOUT`, naming the wheels. Their libraries live under
236
+ `opt/lib`, which kivyforge cannot load from. Before, the build failed with
237
+ a misleading "ABI content skew" on their `.a` files, or, without those,
238
+ built an app that could not find the libraries.
239
+ - **Added:** a native library built for another architecture than its
240
+ wheel's tag (an x86_64 binary in an `arm64_v8a` wheel) now fails the build
241
+ with `KF-ANDROID-WHEEL-ARCH`, instead of failing to load on the device.
242
+ - **Fixed:** `run -p android --release` without a configured release signing
243
+ identity failed with "Gradle reported success for assembleRelease but no
244
+ artifact is at ...". It said it was signing with the debug keystore, but left
245
+ the APK unsigned; now it signs with the debug keystore.
246
+
247
+ - **Fixed:** libraries a package carries inside its own directory, such as
248
+ `ffmpeg/.libs/libavcodec.so` or `blosc2/lib/libtcc.so`, were staged as
249
+ Python extension modules under new names, so nothing could find them. They
250
+ are now staged under their own names, like a top-level `.libs/`.
251
+ - **Changed:** an extension module named with a suffix CPython on Android does
252
+ not import (a build host's `.cpython-314-x86_64-linux-gnu.so`, or another
253
+ Python version's) now fails the build with `KF-ANDROID-WHEEL-SUFFIX`.
254
+ kivyforge's loader ignored the suffix, so such a wheel used to load under
255
+ kivyforge while being unusable anywhere else.
256
+
257
+ Each auditwheel-repaired wheel carries its own renamed copy
258
+ of the C++ runtime, so an app can load several. That is safe unless C++ objects
259
+ pass between libraries from different wheels; see
260
+ `docs/design/platforms/android/03-artifact-distribution-android.md`.
261
+
262
+ ### Wheels from more package indexes
263
+
264
+ - **Fixed:** wheels hosted on Cloudflare R2, such as the Android Pillow wheels
265
+ on the Kivy School index, locked fine and then failed to download at build
266
+ time with HTTP 403 ([#97](https://github.com/ElliotGarbus/kivyforge/issues/97)).
267
+ The host refuses Python's default `Python-urllib` User-Agent. Every request
268
+ kivyforge makes now identifies itself as `kivyforge/<version>`.
269
+ - **Changed:** when an index publishes no SHA-256 for a wheel, `lock` now says
270
+ so and gives the two fixes: use an index that publishes hashes, or put the
271
+ wheels in a `find_links` directory, where kivyforge hashes them itself. It
272
+ used to suggest re-running with network access, which never helps. The
273
+ requirement itself is unchanged: kivyforge still pins every wheel by
274
+ SHA-256. This only happens with indexes that serve wheel metadata (PEP 658)
275
+ but no hashes, because pip then resolves without downloading the wheel.
276
+
277
+ ### `build` shows its downloads
278
+
279
+ - **Added:** on every platform, `build` (and `run`'s implicit build) now shows a
280
+ progress bar for each Python runtime and wheel it downloads, or a few
281
+ percentage lines when the output is a log. These downloads happen on a first
282
+ build, after `clean --cache`, or with `--no-cache`, and used to be silent.
283
+ - **Changed:** `clean --cache`'s help and the guides now say that pip's own cache,
284
+ which `lock` resolves through, is left alone (`pip cache purge` clears it).
285
+ After `clean --cache`, `lock` usually stays fast and shows no downloads.
286
+
287
+ ### Android: `pyjnius` is included automatically
288
+
289
+ - **Fixed:** an Android app whose dependencies didn't list `pyjnius` built
290
+ without complaint and then crashed at launch with `No module named 'jnius'`
291
+ ([#65](https://github.com/ElliotGarbus/kivyforge/issues/65)). Kivy imports
292
+ pyjnius on Android (to read the screen density, for example) but doesn't
293
+ declare it, because python-for-android always supplied it. Now
294
+ `kivyforge lock -p android` adds it, in the range kivyforge supports
295
+ (`>=1.7.0,<1.9`), when your project doesn't declare it. It is added to the
296
+ Android lock only, so desktop installs are unaffected and you don't need a
297
+ `; sys_platform == 'android'` marker. Declaring it yourself still works and
298
+ chooses the version.
299
+ - **Fixed:** a `pyjnius` requirement whose marker leaves Android out (for
300
+ example `pyjnius; sys_platform == 'win32'`) counted as declared, so nothing
301
+ was added, pip skipped it for Android, and `build` stopped with
302
+ `KF-LOCK-INCOMPLETE`, which re-locking did not cure. A declaration now counts
303
+ only if its marker holds on every ABI being locked; otherwise kivyforge adds
304
+ its own requirement as well.
305
+ - **Migration:** a lock made before this change, without pyjnius, now stops the
306
+ build with `KF-LOCK-INCOMPLETE` (exit 4) instead of producing an app that
307
+ crashes. Run `kivyforge lock -p android --update`. Projects that already
308
+ declare pyjnius need no change.
309
+
310
+ ### Android: `lock` and `build` show their downloads
311
+
312
+ - **Fixed:** `kivyforge lock -p android` printed nothing until it finished, so a
313
+ slow connection looked exactly like a hang
314
+ ([#84](https://github.com/ElliotGarbus/kivyforge/issues/84)). It now reports
315
+ each step, shows each wheel download as a progress bar (or as a few percentage
316
+ lines when the output is a log rather than a terminal), and says it is still
317
+ working after 30 s with nothing else to show. The Gradle step for Maven
318
+ dependencies is announced too.
319
+ - **Added:** before Gradle runs, a missing NDK or CMake at the versions the
320
+ generated build pins is installed with the SDK's `sdkmanager`, with progress
321
+ ([#74](https://github.com/ElliotGarbus/kivyforge/issues/74)). Gradle used to
322
+ download the NDK itself in the middle of the build, a download of several
323
+ hundred MB with no progress shown. Without `sdkmanager`, or with its license
324
+ not accepted, `build` says so and Gradle installs it as before.
325
+ - **Changed:** download progress is drawn by the console layer with Rich, so it
326
+ is a live bar on a terminal and plain lines in CI logs, redirected output and
327
+ under `--no-color`. Progress stays on stderr, so `--json` output is unaffected.
328
+
329
+ ### Android: adding your own resources with `include_files`
330
+
331
+ - **Added:** a guide section,
332
+ [Add Android resources](docs/guides/guides/android/configure.md#add-android-resources):
333
+ stage a folder laid out like an Android `res` folder with
334
+ `dest = "app/src/main/res"`, keeping subfolders and qualifiers.
335
+ ([#71](https://github.com/ElliotGarbus/kivyforge/issues/71))
336
+ - **Added:** a file that replaces one kivyforge generates, such as
337
+ `res/values/styles.xml` or the launcher icon, is now reported
338
+ (`[include] ... replaces the file kivyforge generated`, and
339
+ `KF-ANDROID-INCLUDE-OVERRIDE` under `--json`). It used to be silent.
340
+ - **Added:** the build stops, saying what to fix, when an included
341
+ `strings.xml` or `styles.xml` leaves `res/values/` without `app_name` or
342
+ `Theme.Kivyforge`, which the generated manifest uses. That used to fail
343
+ later in Gradle with an AAPT error that did not mention `include_files`.
344
+ - **Fixed:** a file removed from `include_files`, or from a directory it
345
+ names, is now removed from the generated project on the next build. It used
346
+ to stay, and ship, until `kivyforge clean`.
347
+
348
+ ### Android: `run` follows the app's log
349
+
350
+ - **Changed:** `kivyforge run -p android` now shows the app's log live, the way
351
+ pidcat or Briefcase does, until the app exits or you press Ctrl+C (which stops
352
+ the log and leaves the app running). It used to print one snapshot 25 seconds
353
+ after launch and return, so anything the app logged later, such as a
354
+ traceback from a button press, never appeared, and a slow first start could
355
+ show no Kivy output at all.
356
+ ([#73](https://github.com/ElliotGarbus/kivyforge/issues/73))
357
+ - **Fixed:** the log is now the app's own process (`adb logcat --pid`). The old
358
+ filter matched text in each line, so it let other apps' lines through (any
359
+ line mentioning `SDL` or `kivyforge`) and dropped the app's own Android crash
360
+ report.
361
+ - **Added:** if the app never starts, `run` prints the device log since launch
362
+ and fails, instead of showing an empty capture.
363
+ - **Migration:** a script that runs `kivyforge run -p android` and expects it
364
+ to return must add `--no-follow`, which keeps the one-snapshot behaviour
365
+ (now filtered to the app's process). `run --smoke` is unchanged.
366
+
367
+ ### Android: switching `kivy_generation` no longer needs `kivyforge clean`
368
+
369
+ - **Fixed:** rebuilding after changing `[tool.kivy.android].kivy_generation`
370
+ failed to compile until `kivyforge clean` was run. Going from 3 to 2 failed
371
+ with `duplicate class: org.libsdl.app.SDLInputConnection`, because the SDL3
372
+ Java files were left in the generated project. Going from 2 to 3 failed with
373
+ `cannot find symbol: SDLInputConnection`, because Gradle's incremental
374
+ compiler loses a class that SDL3 moved into its own file. The build now
375
+ removes the other generation's SDL files, and on a generation change it
376
+ discards `app/build` (stopping the project's Gradle daemon first), so that
377
+ one build compiles from scratch. Builds that keep the same generation are
378
+ unaffected. ([#66](https://github.com/ElliotGarbus/kivyforge/issues/66))
379
+
380
+ ### Android: apps relaunch on Android 7, and services can use pyjnius below Android 12
381
+
382
+ - **Fixed:** on Android 7.0 and 7.1 (API 24 and 25), every app crashed on its
383
+ second launch, and every service crashed on start, with
384
+ `NoSuchMethodError: ... toPath()`. The check for an already-unpacked bundle
385
+ used `java.nio.file`, which Android added in 8.0. Only the first launch after
386
+ an install got through.
387
+ - **Fixed:** in a service on Android 7 to 11 (API 24 to 30), `import jnius`
388
+ raised `RuntimeError: pyjnius (Android) could not obtain a JNIEnv`. A service
389
+ now loads the app's SDL library before Python starts, which is how pyjnius
390
+ finds the Java VM. It creates no window.
391
+ - **Fixed:** on Windows, `kivyforge run -p android` could crash with
392
+ `AttributeError: 'NoneType' object has no attribute 'splitlines'` after
393
+ launching the app. adb output is now read as UTF-8.
394
+ - **Added:** `kivyforge run --smoke` also checks a relaunch: it unpacks the
395
+ bundle a second time and expects the already-unpacked bundle to be used. A
396
+ fresh install never takes that path, which is how the Android 7 crash above
397
+ went unnoticed.
398
+
399
+ ### Android: the `android` package is bundled
400
+
401
+ - **Added:** every Android build includes python-for-android's `android`
402
+ package, so code that imports it runs unchanged: `android.permissions`,
403
+ `android.activity`, `android.runnable`, `android.broadcast`,
404
+ `android.darkmode`, `android.storage`, `android.config`, and the package's
405
+ own `mActivity`, `api_version`, `open_url` and the rest. The modules are
406
+ taken unchanged from python-for-android at a pinned revision. plyer's
407
+ Android facades, which import it, can now load. Nothing to add to your
408
+ dependencies, but the package needs `pyjnius`. See
409
+ [Use the android package](docs/guides/guides/android/android-package.md).
410
+ - **Fixed:** on Kivy 2.3.1, tapping a `TextInput` quit the app, and so did the
411
+ back key, `App.stop()` and `App.pause()`: Kivy calls the activity through
412
+ this package. Kivy's Android clipboard provider now loads, and so does its
413
+ Android audio provider when an app selects it with `KIVY_AUDIO`. A
414
+ `TextInput` with `input_type = "number"` (or `"mail"`, `"tel"`, ...) gets
415
+ the matching keyboard.
416
+ - **Changed:** `kivyforge lock` fails with `KF-ANDROID-DEPENDENCY-CONFLICT`
417
+ when a dependency is named `android`, and `kivyforge build` fails with
418
+ `KF-ANDROID-APP-CONFLICT` when `app_dir` has an `android.py` or an `android/`
419
+ package (or with `KF-ANDROID-DEPENDENCY-CONFLICT` when an installed wheel
420
+ provides one). Both exit 1. The bundled package always comes first, so a
421
+ second one would ship and never be imported.
422
+ - **Migration:** remove `android` from your dependencies, for example a
423
+ package index's `android` wheel or an `android` carried over from a
424
+ buildozer `requirements` line. Rename an `android.py` or `android/` of your
425
+ own.
426
+
427
+ ### Android: services have `start`, `stop` and `mService`
428
+
429
+ - **Added:** each generated service class has static `start(context, argument)`
430
+ and `stop(context)` methods. A foreground service also gets the five-argument
431
+ `start(context, icon, title, text, argument)`, which replaces the configured
432
+ notification text for that run, and is started with
433
+ `startForegroundService`. Inside a service,
434
+ `autoclass("org.kivy.android.PythonService").mService` is the running
435
+ service. These match python-for-android's services, so ported code only
436
+ changes the class name to `org.kivy.android.Service<name>`. See
437
+ [Add a background service](docs/guides/guides/android/services.md) and the new
438
+ `examples/mobile/android-services`.
439
+ - **Changed:** stopping a service now ends its process. Before, the service
440
+ stopped but its Python code kept running in the background.
441
+ - **Migration:** none for the intent-based start, which still works. A service
442
+ that relied on running on after it was stopped has to stay started instead.
443
+ pyjnius can reach the VM in a service process only on Android 12 (API 31)
444
+ and later.
445
+
446
+ ### Android: a theme switch no longer quits the app
447
+
448
+ - **Fixed:** switching the phone between light and dark mode quit a kivyforge
449
+ Android app, on Kivy 2.3.1 (SDL2) and Kivy 3.0 (SDL3). Android recreates an
450
+ activity for any configuration change the manifest does not declare, and SDL
451
+ ends the app when its activity is recreated. The generated manifest now
452
+ declares the same `android:configChanges` list as python-for-android,
453
+ including `uiMode`, so a theme switch, a language or font-size change, a
454
+ density change or a split-screen resize reaches the running app instead.
455
+ - **Migration:** none. An app that set its own `android:configChanges` through
456
+ `[tool.kivy.android.manifest].activity` keeps its value.
457
+
458
+ ### Android: Kivy 2.3.1 apps keep clear of the system bars
459
+
460
+ - **Fixed:** on Android 15 and later, an app targeting API 35 or higher is drawn
461
+ edge to edge, under the status bar and the navigation bar. Kivy 2.3.1 can't
462
+ report a safe area, so a `kivy_generation = 2` app's content sat under the
463
+ bars with no way to avoid them. The generated activity now keeps the window
464
+ clear of the bars and the notch on API 30 and higher, with black behind the
465
+ bars and light bar icons. The padding follows rotation, and with
466
+ `fullscreen = true` only the notch is padded. Kivy 3.0 apps are unchanged:
467
+ they stay edge to edge and pad themselves with `kivy.mobile.get_safe_area()`
468
+ ([#63](https://github.com/ElliotGarbus/kivyforge/issues/63)).
469
+ - **Migration:** a generation-2 app's window is now smaller by the bar heights
470
+ (for example 1080x2216 instead of 1080x2400 on a Pixel 8a). An app that
471
+ padded itself for the bars, for example by reading the insets with pyjnius,
472
+ should drop that padding.
473
+
474
+ ### Android: `orientation` is honoured at runtime
475
+
476
+ - **Fixed:** an Android app rotated to any orientation when the phone's
477
+ auto-rotate was on, whatever `[tool.kivy].orientation` said. The manifest
478
+ declared the right orientation, but SDL replaced it when Kivy created its window:
479
+ with no orientation hint and a resizable window, SDL allows every orientation.
480
+ The generated activity now passes `[tool.kivy].orientation` to Kivy as
481
+ `KIVY_ORIENTATION`, the variable python-for-android sets for buildozer apps, so
482
+ SDL requests what the manifest declares. Applies to Kivy 2.3.1 (SDL2) and
483
+ Kivy 3.0 (SDL3).
484
+ - **Migration:** none for most apps. An app that declares `portrait` but relied on
485
+ rotating anyway must now list the orientations it supports.
486
+
487
+ ### Android: `fullscreen` hides the system bars
488
+
489
+ - **Added:** `[tool.kivy.android].fullscreen = true` runs the app with the status
490
+ bar and the navigation bar hidden. A swipe from the edge shows them for a moment.
491
+ This is the counterpart of buildozer's `fullscreen = 1`, and `kivyforge init`
492
+ now names it when it finds a `buildozer.spec`. Works on both Kivy 2.3.1 (SDL2)
493
+ and Kivy 3.0 (SDL3).
494
+ - **Migration:** none for existing projects: the default is `false`, which is
495
+ today's behaviour. buildozer treats a missing `fullscreen` as `1`, so an app
496
+ migrated from buildozer that never set the key needs `fullscreen = true` to keep
497
+ hiding the bars.
498
+
499
+ ### Android and iOS: a failed download is reported, not a traceback
500
+
501
+ - **Fixed:** when an Android or iOS build could not download a locked artifact (for
502
+ example, a wheel host answering `HTTP Error 503`), or the download failed its
503
+ SHA-256 check, kivyforge crashed with a Python traceback. Under `--json`, stdout
504
+ was empty instead of one envelope. Both are now reported as an ordinary error
505
+ naming the artifact's URL and the reason, as the desktop backends already did:
506
+ `KF-ERROR` and exit `1`, with a `--json` envelope.
507
+ - **Migration:** none needed. A download error is usually transient: retry the
508
+ build.
509
+
510
+ ### Android builds refuse to start Gradle without a JDK
511
+
512
+ - **Fixed:** a `build -p android --debug` (or `package`, `run`) attempted with only a
513
+ JRE installed started a Gradle daemon, and that daemon outlived the failed build.
514
+ After installing a JDK at the same path (as Debian's `openjdk-21-jdk-headless`
515
+ does), the next build still failed with "does not provide the required
516
+ capabilities: [JAVA_COMPILER]" until `kivyforge clean` stopped the daemon.
517
+ Every Android verb that runs Gradle now checks first, the same way `doctor`
518
+ does, and fails before Gradle starts when there is no `java` or the `java` Gradle
519
+ would run has no `javac` beside it. (Issue #61.)
520
+ - **Changed:** those two cases now fail with `KF-TOOLCHAIN-MISSING` and exit `3`
521
+ ("fix the machine"), with `context.tool` set to `java` or `javac`. Before, Gradle
522
+ ran and failed with `KF-BUILD-TOOL-FAILED` and exit `5`. A JDK of an unsupported
523
+ version is still reported by Gradle, as before.
524
+ - **Migration:** a script that treated exit `5` as "no JDK" should check for exit
525
+ `3` and `KF-TOOLCHAIN-MISSING`. If a daemon from an earlier kivyforge release is
526
+ already stuck, run `./gradlew --stop` in `<app>-android/` once (or
527
+ `kivyforge clean`).
528
+
529
+ ### `doctor -p android`: fail a JRE with no `javac`
530
+
531
+ - **Fixed:** with only a JRE installed (for example Debian's `openjdk-21-jre-headless`),
532
+ `kivyforge doctor -p android` reported the JDK check as passed, because the
533
+ version is in range. The build then failed at `compileDebugJavaWithJavac` with
534
+ "does not provide the required capabilities: [JAVA_COMPILER]". The JDK check now
535
+ also requires a `javac` beside the `java` Gradle will run (following symlinks, as
536
+ Debian's `/usr/bin/java` needs), and fails with a hint to install a full JDK.
537
+ (Issue #47.)
538
+ - **Migration:** none needed. If `doctor` now fails the JDK check, install a JDK
539
+ (`sudo apt install openjdk-21-jdk-headless` on Debian or Ubuntu) and point
540
+ `JAVA_HOME` at it.
541
+
542
+ ### Android: BOMs and Gradle plugins (enables Firebase)
543
+
544
+ - **Added:** `[tool.kivy.android.gradle].platforms` lists BOM coordinates, such as
545
+ `com.google.firebase:firebase-bom:34.15.0`. Each is imported with Gradle's
546
+ `platform()`, and a `dependencies` entry may then omit its version
547
+ (`com.google.firebase:firebase-analytics`). `kivyforge lock` records the version
548
+ the BOM chose for each library, with its SHA-256. The BOM needs an exact version.
549
+ - **Added:** `[tool.kivy.android.gradle.plugins]` maps a Gradle plugin ID to an
550
+ exact version, for example `"com.google.gms.google-services" = "4.4.2"`. Plugins
551
+ are applied after the Android plugin, in the order listed. With
552
+ `include_files` staging `google-services.json`, this is everything Firebase
553
+ needs. A plugin's version is pinned, but no hash is recorded for it, the same as
554
+ for the Android Gradle plugin.
555
+ - **Migration:** none needed. Projects without these keys generate the same
556
+ Gradle files and the same lock as before.
557
+
558
+ ### `doctor`: no more iOS failures off a Mac
559
+
560
+ - **Fixed:** `kivyforge doctor` with no `-p` on a project whose only overlay is
561
+ `[tool.kivy.android]` (or any single non-host platform) fell back to iOS and reported
562
+ `missing [tool.kivy.ios] table`, `Xcode not found` and `xcode-select path not set`,
563
+ none of which the user can or should act on. It now uses the project's only
564
+ configured platform, and for a bare environment check or an ambiguous project on
565
+ Windows or Linux, the host's own platform. iOS remains the fallback on macOS.
566
+ - **Migration:** none needed. Pass `-p` or set `KIVYFORGE_PLATFORM` to pick a platform
567
+ explicitly, as before.
568
+
569
+ ### Android: SDK license guidance for command-line tools 23+
570
+
571
+ - **Fixed:** the `doctor` "SDK licenses" hint, the README, and the Android quickstart
572
+ told you to run `sdkmanager --licenses`. In command-line tools 23 and later
573
+ `sdkmanager` is a wrapper around Google's Android CLI, and `--licenses` does nothing
574
+ (exit 0, no license recorded), so the warning never cleared. The hint now says to
575
+ install any package (such as `sdkmanager platform-tools`), which records the license;
576
+ `--licenses` is still named for older tools.
577
+ - **Docs:** the quickstart has a new "SDK licenses and `sdkmanager`" section. It also
578
+ notes that the new `sdkmanager` exits 0 when an install fails, and that the Android
579
+ CLI collects usage data unless run with `--no-metrics`.
580
+ - **CI:** the jobs that install the pinned NDK, CMake, platform, and build-tools now
581
+ assert each package landed, because a failed install no longer fails the step.
582
+ - **Migration:** none needed.
583
+
584
+ ### Android: doctor checks CMake
585
+
586
+ - **Added:** `kivyforge doctor` now checks for the CMake the native launcher
587
+ compile needs. It used to be missing from the checks, so Gradle downloaded it
588
+ silently during the first build. A missing CMake is a warning with the exact
589
+ `sdkmanager 'cmake;3.22.1'` command.
590
+ - **Changed:** the generated `app/build.gradle` pins `externalNativeBuild.cmake.version`
591
+ to `3.22.1` (AGP's own default), so the build and `doctor` ask for the same package.
592
+ - **Migration:** none needed. A build still downloads CMake itself when it is missing
593
+ and the SDK licenses are accepted.
594
+
595
+ ### Android: compile Java at level 17
596
+
597
+ - **Changed:** the generated `app/build.gradle` now sets `sourceCompatibility` and
598
+ `targetCompatibility` to `VERSION_17` (was `VERSION_1_8`). JDK 21+ reports
599
+ source/target 8 as obsolete on every build; kivyforge already requires JDK 17+,
600
+ so no new JDK is needed.
601
+ - **Migration:** none needed. Regenerate the project (`kivyforge build`) to pick it up.
602
+
603
+ ### Android: accept pyjnius 1.8
604
+
605
+ - **Changed:** the bootstrap's pyjnius `invoke0` range is now `>=1.7.0,<1.9`
606
+ (was `<1.8`). pyjnius 1.8.0 is the first release with Android wheels on PyPI, so
607
+ a bare `pyjnius` dependency re-locks to it, and `build` and `doctor` used to
608
+ reject that lock.
609
+ - **Fixed:** the `build`/`doctor` message for an out-of-range pyjnius said to
610
+ re-lock, which picks the same version again. It now says to constrain pyjnius in
611
+ `[project].dependencies`.
612
+ - **Migration:** none needed. Projects locked to 1.7.x keep working.
613
+
614
+ ### `lock` (Android): warn when `kivy_generation` disagrees with the locked Kivy
615
+
616
+ - **Added:** `kivyforge lock -p android` now warns (and records a `KF-LOCK-WARNING`
617
+ diagnostic under `--json`) when `[tool.kivy.android].kivy_generation` does not
618
+ match the Kivy it resolved, for example `kivy_generation = 3` locking Kivy
619
+ 2.3.1. Previously only `doctor` noticed, after the lock was written. The lock is
620
+ still written.
621
+ - **Docs:** `kivy_generation` selects the SDL bootstrap only; it never influences
622
+ resolution. The Kivy version comes from `[project].dependencies`, so Kivy 3.0
623
+ needs a requirement that admits it, such as `"kivy>=3.0.0.dev0,<4"`.
624
+
625
+ ### `init`: documented `[tool.kivy]`, and templates that fit each platform
626
+
627
+ - **Changed:** `[tool.kivy]` now carries a comment on every key.
628
+ `orientation` is written only when a mobile platform is being seeded, since
629
+ only the iOS and Android backends read it. Seeding several platforms at once
630
+ now writes iOS and Android first, so the shared table keeps `orientation`.
631
+ - **Changed:** the `exclude` list in the desktop (macOS, Linux, Windows)
632
+ templates is now an optional, commented-out size trim. It used to be active
633
+ and dropped `requests` and its dependencies, which breaks `UrlRequest`. iOS
634
+ and Android keep the active list.
635
+ - **Changed:** the iOS and Android templates write `extra_index_urls` for the
636
+ kivy-mobile-wheels index uncommented. Without it `kivyforge lock` cannot find
637
+ a Kivy wheel. `init` now assumes Kivy is a dependency: the `exclude` list and
638
+ this line are always written, instead of only when `[project].dependencies`
639
+ names `kivy`. The Linux template notes that `archs = ["aarch64"]` targets a
640
+ Raspberry Pi.
641
+ - **Fixed:** the "no pyproject.toml" and "found requirements.txt" messages
642
+ suggested `kivy>=3.0`, which has no desktop wheel yet. They now suggest
643
+ `kivy>=2.3.1` and say an iOS app needs Kivy 3.0.
644
+ - **Migration:** existing projects are untouched. A project that relied on the
645
+ desktop `exclude` default should add it back by hand.
646
+
647
+ ### `lock`: the resolver error names the package and says what to do
648
+
649
+ - **Changed:** when pip cannot resolve a dependency for a mobile or desktop
650
+ target, `kivyforge lock` now names the package in its own headline (for
651
+ example `no android_24_arm64_v8a wheel for 'numpy'`) instead of leaving it in
652
+ pip's output further down. For Android it first suggests the first-party
653
+ kivy-mobile-wheels index (`extra_index_urls`) when it is not configured, and
654
+ otherwise `find_links` or dropping the dependency. The iOS error gives the
655
+ same index hint. Error codes are unchanged.
656
+ - **Docs:** the README's Android quick start now explains that Kivy has no
657
+ Android wheel on PyPI, shows the `extra_index_urls` line, and says `lock` uses
658
+ kivyforge's own pip, not the app environment's. The `init` template comment
659
+ for that line no longer says "until they are on PyPI".
660
+
661
+ ### `run`: progress goes to stderr
662
+
663
+ - **Changed:** `kivyforge run` printed its own progress (`[run]`/`[smoke]`
664
+ lines, `Installing on ...`, `Launching ...`, and every line of the build it
665
+ runs first) to stdout. That now goes to stderr, as it does for `build` and
666
+ `package`. stdout carries only what the command produces: the app's own
667
+ output on desktop, the app's filtered logcat on Android, the app console on
668
+ iOS, and "Contract smoke test PASSED." for `--smoke`. On iOS the app's
669
+ output arrives as Apple's launch tool delivers it: the simulator merges the
670
+ app's stdout and stderr onto stdout, while a device keeps them apart, so
671
+ Kivy's log (which Kivy writes to stderr) shows on stderr, and `devicectl`
672
+ adds two lines of its own to stdout.
673
+ - **Migration:** a script that captured `run`'s stdout to read build progress
674
+ should read stderr instead. One that only checked the exit status, or read
675
+ the app's output or the smoke verdict, is unaffected.
676
+
677
+ ### Android: App Bundles are now checked in CI
678
+
679
+ - Google Play requires an App Bundle (`.aab`) for new apps, but no CI job
680
+ built one: every Android job packaged an APK, one ABI at a time. A new
681
+ `android_bundle` job now runs `kivyforge package -p android -f aab` with both
682
+ default ABIs and checks the result: every ABI complete and shipping the same
683
+ native libraries, the byte-compiled payload, the merged manifest, the
684
+ bundle's signature (`jarsigner -verify`), and that the APKs Play generates
685
+ will still extract native libraries, which kivyforge's Python loader
686
+ requires.
687
+ - The post-build checks now understand packages with more than one ABI. A
688
+ correct two-ABI package used to fail them.
689
+ - Test-only; no change to what kivyforge builds.
690
+
691
+ ### Android `doctor` checks the JDK's version and finds the SDK on macOS
692
+
693
+ - **Fixed:** `doctor -p android` passed any `java` that existed. On a Mac
694
+ with no JDK, Apple's `/usr/bin/java` stub passed, and so did Android
695
+ Studio's bundled JDK 25, which the pinned Gradle 8.11.1 cannot run on. The
696
+ build then failed with "Unsupported class file major version". `doctor` now
697
+ runs `java -version` and requires a JDK from 17 to 23.
698
+ - **Fixed:** with `ANDROID_HOME` unset, kivyforge did not look in
699
+ `~/Library/Android/sdk`, where Android Studio installs the SDK on macOS.
700
+ `doctor`, the build's `sdk.dir` and `run`'s `adb` lookup now find it.
701
+ - The docs said "JDK 17 or later". The range is now stated once, in the
702
+ Android supported-versions table, which the other pages link to. Those
703
+ pages note that Android Studio's bundled JDK may fall outside it and that
704
+ `doctor` checks.
705
+ - **Fixed:** `run -p android --smoke` without `--release` staged the release
706
+ payload, so with the default `byte_compile = "release"` it tested
707
+ byte-compiled, stripped Python inside a debug APK. It now stages the debug
708
+ payload, the same Python `run` installs. `--smoke --release` is unchanged.
709
+
710
+ ### The missing-`pyproject.toml` hint no longer points at `init` to create one
711
+
712
+ - **Fixed:** a verb run without a `pyproject.toml` suggested running
713
+ `kivyforge init` to create one, but `init` does not create one: it stops
714
+ and asks for a `[project]` table first. The hint now says to write the
715
+ `[project]` table, then run `kivyforge init -p <platform>`.
716
+
717
+ ### The dice-roller example no longer names the author's Developer ID
718
+
719
+ - **Changed:** `examples/desktop/dice-roller` no longer has a
720
+ `[tool.kivy.macos.signing]` table, so `package -p macos` ad-hoc signs it
721
+ on any Mac. Before, the table named the author's certificate, and the
722
+ desktop quickstart told readers to delete it before locking. That step is
723
+ gone.
724
+
725
+ ### A `pyproject.toml` saved with a byte-order mark loads
726
+
727
+ - **Fixed:** a `pyproject.toml` that starts with a UTF-8 byte-order mark
728
+ failed with "invalid TOML: Invalid statement (at line 1, column 1)". Some
729
+ editors write one, and so does PowerShell's `-Encoding utf8`. kivyforge
730
+ now ignores it.
731
+ - Adding or removing the mark does not make an existing lock stale.
732
+
733
+ ### Pillow is a core dependency; the `linux`, `windows` and `android` extras are gone
734
+
735
+ - **Changed:** Pillow is now installed with kivyforge. Before, a project that
736
+ set an icon or splash image for Android, Linux or Windows needed the
737
+ matching extra, and without it the build stopped partway through.
738
+ - **Removed:** the `linux`, `windows` and `android` extras. Their only
739
+ content was Pillow.
740
+ - **Migration:** install plain `kivyforge`. An old command such as
741
+ `pip install "kivyforge[android]"` still works: pip warns that the extra
742
+ does not exist and installs kivyforge with Pillow.
743
+
744
+ ### `init`: the buildozer.spec key map names real keys
745
+
746
+ - **Fixed:** when `init` finds a `buildozer.spec` and no `pyproject.toml`,
747
+ it prints how each buildozer setting maps onto kivyforge. Several entries
748
+ pointed at keys kivyforge does not read:
749
+ - `android.gradle_dependencies` now maps to `[tool.kivy.android.gradle].dependencies`.
750
+ - `android.add_jars` now maps to `[tool.kivy.android.native.jars]`.
751
+ - `android.add_activities` now maps to `[[tool.kivy.android.activities]]`.
752
+ - `android.add_src` is no longer listed as unsupported. It maps to
753
+ `[tool.kivy.android.src].java`.
754
+ - The map now also covers `android.add_aars`,
755
+ `android.add_gradle_repositories`, `android.add_assets`,
756
+ `android.add_resources`, `android.manifest.intent_filters`,
757
+ `android.manifest_placeholders`, `android.allow_backup`,
758
+ `android.apptheme`, `android.numeric_version`,
759
+ `android.presplash_color` and the adaptive icon layers.
760
+ - The closing reference link now points at the user reference,
761
+ `docs/guides/reference/pyproject/android.md`.
762
+
763
+ ### iOS: `run --device` builds for the phone it installs on
764
+
765
+ - **Fixed:** with automatic signing, `run -p ios --device` could build and
766
+ sign successfully, then fail to install with "This provisioning profile
767
+ cannot be installed on this device". This happened on any phone added
768
+ after Xcode last created the managed profile. The build targeted any iOS
769
+ device, so Xcode kept the old profile. `run --device` now chooses the phone
770
+ before building and passes it to `xcodebuild` as `-destination`, so Xcode
771
+ adds the phone to the managed profile, or stops the build with an error
772
+ naming the phone.
773
+ - A missing phone is now reported before the build instead of after it.
774
+ `build --device` has no target phone and is unchanged.
775
+ - Adding a phone to the profile requires an Apple account signed in to
776
+ Xcode (**Xcode > Settings > Accounts**). Without one, the build now fails
777
+ with Xcode's "No Accounts" error instead of producing an app the phone
778
+ refuses.
779
+
780
+ ### iOS: unpinning a provisioning profile takes effect
781
+
782
+ - **Fixed:** after removing `provisioning_profile` (or clearing `team_id`),
783
+ the next build still carried the old value in the generated `.xcodeproj`,
784
+ which kivyforge updates in place rather than recreating. With
785
+ `auto_signing = true`, Xcode then failed with "conflicting provisioning
786
+ settings". This is the fix kivyforge itself suggests when it refuses an
787
+ Xcode-managed profile. Build settings kivyforge owns are now removed from
788
+ the project when the configuration no longer sets them. Settings kivyforge
789
+ does not own, including any set in Xcode's editor, are left alone.
790
+ - **Migration:** none. A project left in this state is repaired by the next
791
+ `build`; deleting `<app>-ios/` is no longer needed.
792
+
793
+ ### iOS: `run --device` finds the phone on Xcode 27
794
+
795
+ - **Fixed:** with Xcode 27, `run -p ios --device` refused a single connected
796
+ phone with "multiple paired iOS devices found", because Xcode 27's
797
+ `devicectl` also lists simulators as paired iOS devices. `--device` now
798
+ ignores simulators, so one connected phone is picked without
799
+ `--destination`.
800
+ - **Fixed:** `--destination` rejected the UDID that `run --list-devices`
801
+ prints. It now accepts the UDID, as well as the name and devicectl's own
802
+ identifier.
803
+ - `--device --destination` matches only iOS devices, so a name fragment such
804
+ as your first name no longer picks a paired Apple Watch. A destination that
805
+ names a simulator now says to use `--simulator` instead of "no device
806
+ matches".
807
+
808
+ ### iOS: a pinned profile Xcode will refuse stops the build up front
809
+
810
+ - **Changed:** a device or release build, `run --device`, and `package` now
811
+ stop before `xcodebuild` in two cases where Xcode refuses the pinned profile.
812
+ Before, both built the whole app and then failed (exit 5) with Xcode's error,
813
+ while `doctor` reported PASS:
814
+ - `provisioning_profile` set with `auto_signing = true` (the default). Xcode
815
+ rejects a pinned profile under automatic signing.
816
+ - an Xcode-managed profile (`iOS Team Provisioning Profile: ...`, the kind
817
+ automatic signing installs) pinned under `auto_signing = false`. Manual
818
+ signing requires a profile created at developer.apple.com.
819
+ - `doctor -p ios` now FAILs the Provisioning profile check in both cases.
820
+ - `package` now runs the entitlements check that `build` already ran, so an
821
+ entitlement the pinned profile does not grant fails before the archive
822
+ instead of at export.
823
+ - **`KF-ENTITLEMENTS-UNGRANTED` is retired.** It warned about ungranted
824
+ entitlements under automatic signing with a pinned profile, a combination
825
+ that never built. It is no longer emitted and will not be reused.
826
+ - **Migration:** if you pin `provisioning_profile`, set `auto_signing = false`
827
+ and pin a manually created profile; or remove `provisioning_profile` and let
828
+ Xcode manage signing. Re-lock afterwards. Simulator builds are unaffected.
829
+
830
+ ### iOS: `run` streams the app's console
831
+
832
+ - **Fixed:** `run -p ios` launched the app but never showed its output, and
833
+ Ctrl+C discarded it; the quickstart said it streamed. The launch now runs
834
+ attached to your terminal, as macOS `run` does, until the app exits or you
835
+ press Ctrl+C. On a device the launch passes `devicectl --console`, which
836
+ attaches to the app's output and waits for it to exit.
837
+
838
+ ### iOS: `--arch` offers only the simulator slice kivyforge pins
839
+
840
+ - **Fixed:** `build -p ios --arch aarch64` suggested `x86_64`, which then
841
+ crashed with a traceback (no `--json` envelope) because no lock pins an
842
+ x86_64 simulator slice. The error now suggests `arm64` only.
843
+ - On an Intel Mac, a simulator build fails before downloading anything, with
844
+ exit 3 (`KF-HOST-INCAPABLE`), and says to build for a device or on Apple
845
+ Silicon. Device builds on an Intel Mac are unaffected.
846
+ - A wheel the lock does not cover for the requested slice is now a
847
+ configuration error with a `--json` envelope, and says to re-lock.
848
+
849
+ ### macOS and Linux: the built bundle is readable by other users
850
+
851
+ - **Fixed:** the macOS `.app` and the Linux AppDir were created mode `0700`,
852
+ so only the user who built them could open them, and `cp -R` carried that
853
+ into a DMG or `/Applications`. They now get the mode a plain `mkdir` would
854
+ (`0755` under the usual umask). Rebuild to pick it up.
855
+
856
+ ### CLI: help text matches what each option does
857
+
858
+ - **Fixed:** the top-level help called kivyforge "a declarative iOS bundler";
859
+ it now names all five platforms. Its em dash also printed as `ΓÇö` when help
860
+ was piped on Windows; help text is now ASCII-only, and a test keeps it so.
861
+ - `open` help, and its error on platforms without an IDE project, now say it
862
+ opens Xcode for iOS and Android Studio for Android.
863
+ - `--team-id`, `--signing-identity`, and `--export-method` now say which
864
+ platforms read them. `package --signing-identity` applies to iOS and macOS
865
+ only; Windows signs with `[tool.kivy.windows.signing].thumbprint`, and
866
+ Android with `--keystore`.
867
+ - **Changed:** `build` and `package` now refuse those options, and `package`'s
868
+ `--notarize`/`--no-notarize`/`--notary-profile`, on a platform that does not
869
+ read them, as they already refused Android-only options elsewhere. Before,
870
+ `package -p windows --signing-identity X` succeeded and signed nothing with
871
+ X. The error names each option and the platforms it applies to (exit 1).
872
+ - **Migration:** a script that passes one of these to a platform that ignores
873
+ it, such as one command line shared across targets, now fails; drop the
874
+ option for that platform. Nothing it did changes: the option was never
875
+ applied there.
876
+
877
+ ### Config: unknown keys under `[tool.kivy]` are errors
878
+
879
+ - **Changed:** a key kivyforge does not recognise anywhere under `[tool.kivy]`
880
+ now fails every verb with a configuration error (exit 1). Before, it was
881
+ dropped without a word and the build went ahead as if it had never been
882
+ written: a typo such as `deployment_targt`, or `[tool.kivy.android.proguard]`,
883
+ which the Android spec describes but no release implements, so a release
884
+ build shipped with none of the keep rules it declared.
885
+ - The error names the key and its line, and suggests the closest valid key
886
+ (`did you mean 'deployment_target'?`) or lists the valid ones. All unknown
887
+ keys are reported in one run.
888
+ - Not checked: keys outside `[tool.kivy]`; tables passed through to another
889
+ tool (`info_plist`, `entitlements`, `xcode.build_settings`, the Android
890
+ `manifest` attribute tables, `gradle_properties`); and a table for a platform
891
+ kivyforge does not support yet, such as `[tool.kivy.web]`, which spec 01
892
+ promises is inert. Targeting a misspelt overlay now names it:
893
+ `found [tool.kivy.andriod]; rename it to [tool.kivy.android]`.
894
+ - **Migration:** a project with an unknown key stops building until the key
895
+ is fixed or removed. No setting changes meaning: every key the error names
896
+ was already being ignored. Remove `[tool.kivy.android.proguard]` if you
897
+ set it; it never took effect.
898
+
899
+ ### Windows: `package` warns when a bundle only fits in a short folder
900
+
901
+ - Windows limits a path to 259 characters unless long paths are enabled, and
902
+ they are **off** by default. Every file in an app has to fit, *including*
903
+ the folder the user unzips or installs it into, so the deepest path inside
904
+ the bundle decides how long that folder can be.
905
+ - `kivyforge package -p windows` now measures this. When the bundle leaves
906
+ less than 100 characters for its folder, it prints a warning naming the
907
+ deepest path and the longest folder that will work, and reports
908
+ **`KF-PATH-DEPTH`** in `--json` output. A typical Kivy app leaves about 154,
909
+ so most projects will never see it; deep dependency trees can.
910
+ - Measured, not estimated: with long paths off, a bundle in a folder of
911
+ exactly the reported length works, and one character longer does not.
912
+ - No change to the launcher. Declaring it `longPathAware` would not help:
913
+ Windows refuses to start an executable from a folder too long for its own
914
+ path even with long paths enabled, and the bundled `python.exe`, which does
915
+ the file access, already opts in.
916
+
917
+ ### iOS: `provisioning_profile` works as documented
918
+
919
+ - **Fixed:** `[tool.kivy.ios.signing].provisioning_profile` was read two
920
+ incompatible ways. Xcode received it as a profile name or UUID (the
921
+ documented form), but `doctor` and the entitlements pre-flight treated it as
922
+ a file path. A name or UUID made `doctor` FAIL ("not found") and silently
923
+ skipped the entitlements check; a path passed `doctor` and then failed the
924
+ Xcode build.
925
+ - A name or UUID is now looked up among the profiles installed on the Mac, so
926
+ `doctor` and the entitlements check use the same profile Xcode signs with.
927
+ - A path to a `.mobileprovision` is also accepted: kivyforge reads the file and
928
+ passes its UUID to Xcode. `doctor` warns if that profile is not installed,
929
+ since Xcode signs only with installed profiles.
930
+ - **Migration:** none for the documented name/UUID form. If you set a path,
931
+ it keeps working, and now also reaches Xcode correctly.
932
+
933
+ ### Linux: `--arch aarch64` is accepted
934
+
935
+ - **Fixed:** `build` and `package` rejected `--arch aarch64` as a usage error,
936
+ although the Linux spec documents `package -p linux --arch aarch64`. With
937
+ `archs = ["x86_64", "aarch64"]` the Raspberry Pi AppImage could only be
938
+ produced by reordering the list. The shared `--arch` choices now include
939
+ `aarch64`; with no `--arch`, the first locked arch is still the default.
940
+ - `run` still does not accept `aarch64`: that arch is cross-built only, and
941
+ `run` launches the result on the build host.
942
+ - `build -p ios --arch aarch64` now fails with a clear message instead of
943
+ deriving a nonexistent iOS platform tag.
944
+
945
+ ### Install: pip is now a dependency
946
+
947
+ - **Fixed:** `uv tool install kivyforge` produced an install where every
948
+ `kivyforge lock` failed. kivyforge runs `python -m pip` to resolve and stage
949
+ wheels, and uv tool environments ship without pip. The failure was also
950
+ misleading: it reported that a dependency had no wheel upstream.
951
+ - kivyforge now depends on `pip>=25.1` (the Android resolver's floor, which
952
+ also covers iOS's 24.3), so every installer, including uv and pipx, gets a
953
+ pip new enough for every target.
954
+
955
+ ### Docs: end-user documentation site (MkDocs Material)
956
+
957
+ - **Added:** a task-based user guide — installation, per-platform quickstarts,
958
+ concepts, per-platform how-to guides, a full configuration/CLI reference, and
959
+ troubleshooting — built with MkDocs Material and published to GitHub Pages
960
+ (roadmap item 6). Sources live in `docs/guides/`; the design documents under
961
+ `docs/design/` stay unpublished.
962
+ - The host matrix, exit codes, and `KF-*` diagnostic vocabulary are generated at
963
+ build time from kivyforge's own `capabilities`/`report` modules, and the CLI
964
+ reference from the click command tree, so the site cannot drift from the tool.
965
+ `mkdocs build --strict` runs in CI and fails on a broken internal link, a
966
+ missing nav page, or a `KF-*` code the reference does not document.
967
+
968
+ ### Desktop: clear error when the runtime can't be staged on a case-insensitive filesystem
969
+
970
+ - **Fixed:** every python-build-standalone Linux runtime ships 25 pairs of
971
+ paths that differ only by case, all in `python/share/terminfo`
972
+ (`h/hp70092A` beside `h/hp70092a`). Building a Linux app onto a
973
+ case-insensitive filesystem, such as `/mnt/c` from WSL2, used to die partway
974
+ through staging with a bare `shutil.Error`. Worse, extracting straight onto
975
+ such a filesystem silently overwrote one file of each pair.
976
+ - Staging now checks the runtime archive **before** extracting it, and stops
977
+ with the number of colliding paths, an example pair, the directory, and what
978
+ to do instead (under WSL2: build from the Linux side, e.g. under `~`).
979
+ - Applies to the Linux, macOS and Windows runtime stagers. The filesystem is
980
+ only probed when an archive actually has such collisions; no macOS or
981
+ Windows runtime measured so far does, so those builds are unaffected.
982
+
983
+ ### Desktop: `kivyforge run --release` (Linux, macOS, Windows)
984
+
985
+ - **`run --release` now works on the desktop backends**, as it has on Android
986
+ since the entry below. Previously `run` on Linux, macOS and Windows always
987
+ built the dev flavor, so `byte_compile`/`strip_source` (both release-only by
988
+ default) could only be reached through `kivyforge package` — never through
989
+ the command used for day-to-day iteration. That gap is where the Linux
990
+ `AppRun` defect lived: shipped, reproducible in one command, and invisible
991
+ to every verb a developer runs while working.
992
+ - The release flavor is built into the same `build/<platform>/` tree `run`
993
+ always launches, so a later plain `run` rebuilds it with readable source.
994
+ - `--release --no-build` is refused: `--no-build` launches whatever the last
995
+ build left, and nothing records whether that was a release build.
996
+ - `run -p ios --release` is refused rather than ignored — an iOS release build
997
+ is an archive and a signed `.ipa`, not a simulator install. Use
998
+ `kivyforge build --release` or `kivyforge package -p ios`.
999
+
1000
+ ### `kivyforge lock` honors `GH_TOKEN` / `GITHUB_TOKEN`
1001
+
1002
+ - **Fixed:** resolving the python-build-standalone runtime queries GitHub's
1003
+ API, which allows only **60 requests/hour per IP** unauthenticated — enough
1004
+ for a dev box, not for CI, where a shared runner egress address can exhaust
1005
+ it and fail the lock with `HTTP Error 403: rate limit`. A single resolve can
1006
+ spend up to 16 of those requests.
1007
+ - `lock` (and `lock --check`, which re-resolves) now sends `GH_TOKEN` or
1008
+ `GITHUB_TOKEN` as a bearer token when either is set, raising the ceiling to
1009
+ 5000/hour. `GH_TOKEN` takes precedence, matching the `gh` CLI. An empty or
1010
+ whitespace-only value is ignored rather than sent, so an unset CI secret
1011
+ degrades to an anonymous request instead of a 401.
1012
+ - No configuration is needed to keep the old behavior: with neither variable
1013
+ set, the request is anonymous exactly as before.
1014
+ - On GitHub Actions, `env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}` needs no
1015
+ setup. A rate-limited failure now says so in its error message.
1016
+
1017
+ ### Android: manifest passthrough values were escaped twice
1018
+
1019
+ - **Fixed:** a value in `[tool.kivy.android.manifest.application]` or
1020
+ `[tool.kivy.android.manifest.activity]` containing `&`, `<` or `>` reached
1021
+ the device with the escape still in it — `android:description = "Rock &
1022
+ Roll"` shipped as the literal text `Rock &amp; Roll`. The value was escaped
1023
+ on its way into the attribute and then escaped again when the attribute was
1024
+ quoted. Values without those three characters were never affected, which is
1025
+ every in-repo example and most real configs.
1026
+ - Found by the new merged-manifest T3 check (below) on its first run.
1027
+
1028
+ ### Android: two new post-build checks in CI
1029
+
1030
+ - The `android_gradle` job now asserts that **AGP's merged release manifest
1031
+ still contains what `pyproject.toml` declared** — applicationId, version
1032
+ code/name, min/target SDK, every declared permission, feature, service,
1033
+ extra activity and intent-filter, and that no `${placeholder}` survived
1034
+ unresolved. The release policy pass already read this manifest to lint its
1035
+ *posture*; nothing checked that the project's own declarations had survived
1036
+ the merge.
1037
+ - The same job now runs **`apksigner verify` on the release APK** at the
1038
+ project's own `min_sdk`, and checks the v1 (JAR) signing scheme against
1039
+ `[tool.kivy.android.signing].v1_signing`.
1040
+ - Both are test-only additions; no behavior change for builds that were
1041
+ already correct.
1042
+
1043
+ ### Android: `kivyforge run --release`
1044
+
1045
+ - **`run --release` now builds and launches the release variant**, not just
1046
+ `--smoke --release`. Previously `run` always built debug, so `byte_compile`/
1047
+ `strip_source` (both release-only by default) could only ever be exercised
1048
+ through `kivyforge package` — never through the command developers actually
1049
+ use for day-to-day iteration.
1050
+ - Skips `package`'s manifest-policy and lint gates (those belong to the
1051
+ distribution path); signing falls back to the debug keystore when release
1052
+ signing isn't configured, so `run --release` never requires release secrets
1053
+ to work.
1054
+
1055
+ ### iOS: a Swift Package with a signable target (e.g. Firebase) now builds for device/release
1056
+
1057
+ - **Fixed:** an iOS app with a Swift Package dependency that has its own
1058
+ signable target (e.g. Firebase's resource-bundle targets, `Firebase_FirebaseCore`)
1059
+ could fail to build with `Signing for "..." requires a development team`,
1060
+ even with automatic signing and a team correctly configured — the app's own
1061
+ target built and signed fine, but Xcode builds a Swift Package's targets as
1062
+ a *separate, synthesized sub-project* that does not inherit signing from
1063
+ either the consuming target's or the project's `.pbxproj` build settings.
1064
+ `DEVELOPMENT_TEAM` now also goes out as an `xcodebuild` command-line
1065
+ override (as `CODE_SIGN_IDENTITY` already did) for `--device` builds and
1066
+ `--release` archives, which is what the package's own targets actually
1067
+ read.
1068
+ - An earlier attempt at this fix (also writing `DEVELOPMENT_TEAM`/
1069
+ `CODE_SIGN_STYLE` to the project's own build configuration, matching what
1070
+ Xcode's UI does when you set a Team in Signing & Capabilities) is kept —
1071
+ it's harmless and correct for the app's own target — but was verified,
1072
+ against the real `firebase-ios-sdk` package, to be **insufficient on its
1073
+ own**: the identical error still reproduced with only that fix in place.
1074
+ - Reported by an early user after adding the Firebase SPM package; reproduced
1075
+ and confirmed fixed against the real package (`FirebaseCore` product,
1076
+ `firebase-ios-sdk` 11.15.0) on a real device build, 2026-09-21.
1077
+
1078
+ ### iOS: a remote Swift Package no longer embeds by default
1079
+
1080
+ - **Changed:** `[tool.kivy.ios.native.swift_packages]`'s `embed` field now
1081
+ defaults to `false` for a `url` (remote) package; a `path` (local) package
1082
+ is unchanged and still defaults to `true`. A remote package's library
1083
+ product is almost always `automatic`, which Xcode resolves to **static**
1084
+ for a standalone consuming target — there's no `.framework` for Xcode to
1085
+ copy, so the old `embed = true` default failed at `xcodebuild build` with
1086
+ `The file "<Product>" couldn't be opened because there is no such file`
1087
+ for most third-party packages, Firebase's included. A local `path` shim is
1088
+ author-controlled (its own `Package.swift` can deliberately declare
1089
+ `type: .dynamic`) and keeps the old default.
1090
+ - **Migration:** if a remote package's product really is a dynamic framework
1091
+ (check its own docs — Sentry's `Sentry` product is one example), set
1092
+ `embed = true` explicitly; it no longer comes for free.
1093
+ - Reported by an early user after adding `FirebaseAuth`; reproduced against
1094
+ the real package and confirmed `embed = false` fixes it. See
1095
+ `docs/design/dev/ios-firebase-spm-signing-findings.md` for the full
1096
+ investigation, including why a reactive fix (matching `xcodebuild`'s error
1097
+ text) was rejected as fragile in favor of this proactive default.
1098
+
1099
+ ### iOS: a missing SDL3 now fails the build, not just the launch
1100
+
1101
+ - **A Kivy iOS app that stages `SDL3.xcframework` now fails to *compile*** if
1102
+ its SDL3 headers are somehow missing (a broken vendoring step, a manually
1103
+ edited `HEADER_SEARCH_PATHS`), with an actionable error naming the cause.
1104
+ Previously this silently compiled the headless (windowless) fallback path
1105
+ instead — an app that launches but can never open a window, with nothing
1106
+ in the build log explaining why.
1107
+ - Non-Kivy (pure-Python) apps are unaffected; the guard only activates when
1108
+ SDL3.xcframework is actually staged.
1109
+ - Credit: [PR #1](https://github.com/ElliotGarbus/kivyforge/pull/1) (kengoon).
1110
+
1111
+ ### `kivyforge init -p` is now repeatable
1112
+
1113
+ - **Seed several platforms in one run:** `kivyforge init -p ios -p android`
1114
+ writes both overlays into `pyproject.toml` in a single call — the shared
1115
+ `[tool.kivy]` table is written once, and each platform's own overlay is
1116
+ added or (with `--force`) regenerated in turn. Previously this took one
1117
+ `init` invocation per platform.
1118
+ - **`--json`'s shape is unchanged for the common, single-`-p` case**
1119
+ (`platform` + `data.action`/`data.tables`). With more than one `-p`, the
1120
+ envelope's `platform` is `null` and results are listed under
1121
+ `data.results` as `{"platform", "action", "tables"}` per platform, in the
1122
+ order given.
1123
+ - Every other verb (`build`, `run`, `package`, `doctor`, `status`, ...)
1124
+ is unaffected — their `-p` still takes exactly one value, as it must.
1125
+
1126
+ ### `entry_point` now runs as `__main__` on every platform
1127
+
1128
+ - **Migration note.** `if __name__ == "__main__":` blocks in your entry
1129
+ module now execute on Android and iOS, matching the behavior Linux, macOS
1130
+ and Windows already had. Previously the entry module was only *imported* on
1131
+ mobile, so that idiom silently never ran there — no error, nothing in the
1132
+ log. If your app already calls `App().run()` unconditionally at module top
1133
+ level (the style every in-repo example uses), nothing changes for you.
1134
+ - **Breaking for one specific pattern:** an `entry_point` pointing at a
1135
+ *package* (not a module) now requires a `__main__.py` on every platform,
1136
+ same as `python -m mypackage`. Before this change, Android and iOS ran the
1137
+ package's `__init__.py` instead. Add a `__main__.py`, or point `entry_point`
1138
+ at an explicitly-named module instead (e.g. `entry_point = "myapp.start"`).
1139
+ - **Also changes:** the entry module is no longer left in `sys.modules` after
1140
+ startup (mobile only — desktop already worked this way). Code that expects
1141
+ to `import` its own entry module again by name after startup will now
1142
+ re-execute it instead of getting the cached one.
1143
+ - Implementation: Android's `main.c` and iOS's `kivyforge_bootstrap.m` both
1144
+ now run the entry module via `runpy.run_module(entry_point,
1145
+ run_name="__main__", alter_sys=True)`. Credit to
1146
+ [PR #1](https://github.com/ElliotGarbus/kivyforge/pull/1) (kengoon), which
1147
+ independently found and fixed the iOS half of this first.
1148
+
1149
+ ### Desktop apps start faster: the embedded stdlib ships compiled
1150
+
1151
+ - **The staged Python stdlib is byte-compiled at build time** on Windows, Linux
1152
+ and macOS. Measured on a packaged `dice-roller`: `import kivy` costs **66 ms
1153
+ instead of 276 ms** — about 210 ms off every launch. Bundles previously
1154
+ shipped the stdlib as source and re-parsed it on each start, which neither the
1155
+ `.AppImage` (read-only) nor the signed `.app` (writing to itself invalidated
1156
+ its signature) could ever cache away.
1157
+ - **Stdlib sources are kept**, unlike the app payload: they are what tracebacks,
1158
+ `inspect` and `linecache` read. `strip_source` still applies only to your app
1159
+ and its site-packages.
1160
+ - Follows the existing `[tool.kivy.<platform>.build_settings].byte_compile`
1161
+ setting, so it applies to `package` by default and to every build when that is
1162
+ `true`. No new option.
1163
+ - The byte-compile subprocess no longer seeds the artifact with an arbitrary
1164
+ handful of its own import caches, so that subtree is reproducible.
1165
+
1166
+ ### Spawned tools can no longer wait for input
1167
+
1168
+ - **Every external tool kivyforge runs is given a closed stdin.** A child that
1169
+ unexpectedly prompts now gets EOF and fails fast, instead of blocking until a
1170
+ CI job times out with nothing explaining why.
1171
+ - **pip is passed `--no-input`** at the lock resolvers and the wheel staging
1172
+ installs: an index that wants credentials is the one case here that genuinely
1173
+ prompts.
1174
+ - **`kivyforge run` is deliberately unchanged** — the app it launches *is* your
1175
+ program and keeps the user's stdin.
1176
+
1177
+ ### Linux aarch64 is a Raspberry Pi *target*
1178
+
1179
+ - **`[tool.kivy.linux].archs` accepts `"aarch64"`** (opt-in; the default stays
1180
+ `x86_64`). Cross-build on a Linux x86_64 host; run the AppImage on a 64-bit
1181
+ Raspberry Pi OS image (Pi 4 or 5). kivyforge never runs on the Pi.
1182
+ **Verified 2026-09-17 on a Pi 5** (Debian 13, labwc/Wayland, Broadcom V3D);
1183
+ a Pi 4 has not been run.
1184
+ - **`appimagetool` is the host-arch binary**; the aarch64 type2 runtime is
1185
+ embedded with `--runtime-file`. 32-bit ARM and musl stay out of scope.
1186
+
1187
+ ### New: `kivyforge capabilities`
1188
+
1189
+ - **A verb that answers what this kivyforge can do**, with no project, lock or
1190
+ network needed — so an agent can ask before it has anything to point at.
1191
+ `--json` publishes:
1192
+ - `platforms[]`: each target's `archs`, `package_formats`,
1193
+ `default_package_format`, aliases, the host it is the default target for,
1194
+ and **`hosts`: which of macOS/Linux/Windows can build it at all**. That last
1195
+ one is the fact that stops an agent attempting iOS on Windows, and nothing
1196
+ in `--help` states it.
1197
+ - `verbs[]`: every registered verb and whether it accepts `--json`.
1198
+ - `exit_codes` and `diagnostic_codes`: the reserved exit taxonomy and the
1199
+ published `KF-*` vocabulary.
1200
+ - Everything is derived rather than restated: the host matrix comes from asking
1201
+ each backend's own `check_host_capability`, the verb list from the click
1202
+ group, the codes from the modules that define them. A hand-kept copy would
1203
+ pass its tests right up until it went stale.
1204
+
1205
+ ### `--json` on `clean`, `init`, `upgrade` and `open`
1206
+
1207
+ - **Every verb but `run` now takes `--json` and `--no-color`.** Each reports what
1208
+ it did rather than that it did something:
1209
+ - `clean`: `data.removed` lists the generated trees actually deleted (relative,
1210
+ posix), plus `cache_flushed` and `gradle_caches`. Recorded as they go, so a
1211
+ removal that fails part way still names what it had removed.
1212
+ - `init`: `data.action` (`added` / `regenerated`), `data.tables` — the
1213
+ `[tool.kivy*]` tables written — and `data.pyproject`.
1214
+ - `upgrade`: `data.refreshed` names each re-fetched artifact and `data.skipped`
1215
+ counts vendored (path-pinned) entries. A hash mismatch half way through still
1216
+ reports the artifacts already refreshed.
1217
+ - `open`: `data.project` is the project that was opened.
1218
+ - **Two new diagnostic codes**, both warnings on an `ok: true` run:
1219
+ `KF-IDE-NOT-FOUND` when `open` finds no Android Studio launcher on PATH (the
1220
+ project is still generated, just not launched), and `KF-DEPENDENCY-DRIFT` when
1221
+ `init` sees an installed dependency outside its declared specifier.
1222
+ - **`open -p ios` now prints the project it opened**, matching what Android has
1223
+ always printed. It used to succeed silently.
1224
+ - As with `build`/`package`, progress moves to stderr on these verbs: `clean`'s
1225
+ "Stopped the project's Gradle daemon(s)." and `upgrade`'s per-artifact
1226
+ "Refreshing …" lines. What each verb *produced* stays on stdout.
1227
+
1228
+ ### Breaking: `build` and `package` progress moves to stderr
1229
+
1230
+ - **For `build` and `package`, everything except the product lines now goes to
1231
+ stderr**, on all five platforms: staging and signing progress, Android's
1232
+ `[collect]`/`[stage]`/`[gradle]`/`[policy]` lines, and Gradle's own output
1233
+ (also for Android `run` and `--smoke`). stdout keeps only what was produced
1234
+ (`Built …`, `Generated …`, `Packaged …`, `Exported …`) and the distribution
1235
+ advice. On a terminal nothing looks different: the text and its order are
1236
+ unchanged.
1237
+ - **Migration:** a job that captures only stdout
1238
+ (`kivyforge package -p android > build.log`) no longer gets the build log.
1239
+ Capture both streams (`> build.log 2>&1`).
1240
+ - **When `xcodebuild` or `appimagetool` fails**, its output is printed as
1241
+ progress and the error is a one-line summary (`xcodebuild archive failed
1242
+ (exit 65); its output is above.`) instead of embedding the whole log.
1243
+ `appimagetool` failures now show both of its streams; stdout used to be
1244
+ dropped whenever stderr had anything in it.
1245
+
1246
+ ### `build --json` and `package --json`
1247
+
1248
+ - Both verbs take `--json` and `--no-color`, like the other verbs. The envelope's
1249
+ `data.artifacts` lists what this run produced, as `{"path", "kind"}` with the
1250
+ path relative to the project root and `kind` one of `appimage`, `apk`, `aab`,
1251
+ `app`, `ipa`, `folder`, `project`.
1252
+ - Only products this invocation finalised are listed, including on failure: a
1253
+ `build` that fails after generating the project still names the project; a
1254
+ `package` that fails names nothing, never a previous run's artifact.
1255
+ - Success-path warnings arrive as diagnostics on an `ok: true` envelope:
1256
+ `KF-SIGNING-UNCONFIGURED`, `KF-BYTECOMPILE-NO-INTERP`, `KF-MANIFEST-POLICY`
1257
+ and `KF-ENTITLEMENTS-UNGRANTED`.
1258
+ - **Failures now say what kind of failure they are.** `build` and `package` used
1259
+ to exit `1` for everything; they now use the reserved exit codes, with a
1260
+ matching diagnostic code:
1261
+
1262
+ | Exit | Code | When |
1263
+ |---|---|---|
1264
+ | `3` | `KF-HOST-INCAPABLE` | wrong host OS for the target |
1265
+ | `3` | `KF-TOOLCHAIN-MISSING` | a tool is not installed (`xcodebuild`, the Gradle wrapper, `clang`, `codesign`, `signtool`, `appimagetool`, …) |
1266
+ | `3` | `KF-TOOLCHAIN-UNUSABLE` | a tool is present but cannot be executed; `context.errno` says why |
1267
+ | `4` | `KF-LOCK-MISSING` / `KF-LOCK-UNREADABLE` / `KF-LOCK-DRIFT` | re-run `kivyforge lock` |
1268
+ | `5` | `KF-BUILD-TOOL-FAILED` | Gradle, `xcodebuild` or `appimagetool` exited non-zero; `context` has `tool` and `task` |
1269
+ | `5` | `KF-ARTIFACT-MISSING` | the tool reported success but the product is not there |
1270
+
1271
+ Anything not listed keeps `KF-ERROR` and exit `1`. A tool that cannot be
1272
+ started at all used to crash with a traceback on iOS and Android; it now
1273
+ fails cleanly with an envelope.
1274
+ - Android now prints `Generated <app>-android` and relative artifact paths, like
1275
+ the other platforms. iOS `build --simulator`/`--device` builds into the
1276
+ project's own `build/DerivedData` (as `run` already did) and prints the
1277
+ `.app` it produced.
1278
+
1279
+ ### Breaking: Apple targets are Apple Silicon only
1280
+
1281
+ - **`x86_64` removed from macOS and the iOS Simulator**, as a host *and* as a
1282
+ target. macOS 27 stops installing on Intel hardware, GitHub's `macos-*-intel`
1283
+ runners sunset in 2027, and macOS 28 removes Rosetta — so an Intel slice is
1284
+ one nothing can execute or validate. Legacy tools continue to cover Intel;
1285
+ a new toolchain does not need to carry it.
1286
+ - `[tool.kivy.macos].archs` accepts only `["arm64"]` (the new default), and
1287
+ `[tool.kivy.ios].simulator_archs` only `["arm64"]`. Both reject `x86_64`
1288
+ with a migration message naming the fix.
1289
+ - **universal2 builds are gone** along with the `lipo` merge machinery, and
1290
+ `--arch universal2` is no longer a CLI choice.
1291
+ - iOS locks now pin **two** slices (device arm64 + simulator arm64) instead
1292
+ of three.
1293
+ - **Migration:** set `archs = ["arm64"]` / `simulator_archs = ["arm64"]` (or
1294
+ drop the keys — arm64 is the default) and re-lock.
1295
+ - **`universal2` *wheels* are unaffected** and still resolve normally — a
1296
+ universal2 wheel contains arm64. The *build target* set narrowed; the
1297
+ *wheel tag* set did not.
1298
+
1299
+ ### Desktop source stripping (Windows/Linux/macOS)
1300
+
1301
+ - **New `[tool.kivy.<platform>.build_settings]` table** on Windows, Linux, and
1302
+ macOS, matching what Android's own `build_settings` already does:
1303
+ `byte_compile` and `strip_source` (each `"release"` | `true` | `false`,
1304
+ default `"release"`). `"release"` applies only to `kivyforge package` —
1305
+ `build`/`run` always keep readable `.py` for fast iteration.
1306
+ - Only the app sources and installed site-packages are compiled/stripped;
1307
+ the staged Python stdlib is never touched (readable tracebacks,
1308
+ `inspect`/`linecache` stay intact).
1309
+ - The compiler is the bundle's own staged interpreter when it can run on
1310
+ the host (never Rosetta or any other emulation), else the interpreter
1311
+ running `kivyforge` itself on a matching CPython minor, else the default
1312
+ degrades to shipping source with a note (`byte_compile = true` fails the
1313
+ build instead of silently shipping source).
1314
+ - On macOS this runs before ad-hoc signing, since codesign seals the
1315
+ bundle.
1316
+ - Previously only PyInstaller (bytecode-only) and Flet (bytecode-only by
1317
+ default since v0.86) did this; kivyforge's desktop backends shipped raw
1318
+ `.py` unconditionally until now.
1319
+
1320
+ ### iOS source stripping
1321
+
1322
+ - **New `[tool.kivy.ios.python.build_settings]` table** (nested under
1323
+ `python`, since `[tool.kivy.ios].build_settings` already names the Xcode
1324
+ passthrough table): the same `byte_compile`/`strip_source` release
1325
+ tri-state as Android and the desktop backends, covering both `pip-deps`
1326
+ (third-party wheels) and the app's own source.
1327
+ - `build`/`run` are unaffected — `app/` stays a symlink to `app_dir` for
1328
+ fast iteration, exactly as before.
1329
+ - `kivyforge package` now stages `app/` as a real, disposable copy instead
1330
+ of a symlink and compiles/strips *that* — the user's actual source tree
1331
+ is never touched. Switching back to `build`/`run` afterward reclaims the
1332
+ copy for the symlink automatically.
1333
+ - The staged `Python.xcframework` stdlib is never touched (it's a
1334
+ prebuilt, opaque library either way).
1335
+ - `Python.xcframework` ships no standalone interpreter to shell out to, so
1336
+ compilation always uses the `kivyforge`-hosting interpreter itself (on a
1337
+ matching CPython minor) or degrades — there is no "staged interpreter"
1338
+ rung the way desktop has.
1339
+
1340
+ ### Android backend (`.apk` / `.aab`)
1341
+
1342
+ - **New `android` target.** `kivyforge lock/build/run/package -p android`
1343
+ resolves into `pylock.android.toml`, assembles the official
1344
+ [python.org Android runtime](https://www.python.org/downloads/android/) (per
1345
+ ABI) plus per-ABI `android_*` wheels into a generated **Gradle/AGP** project,
1346
+ and produces a signed **`.apk`** (sideload/CI) or **`.aab`** (Play upload). A
1347
+ **wheel-assembly + Gradle-drive** backend — no python-for-android recipe
1348
+ system, no per-app C-extension compilation. Builds on Windows, macOS, or Linux
1349
+ (consumes prebuilt wheels + runtime; drives the SDK/NDK/Gradle). 64-bit only
1350
+ (`arm64_v8a`, `x86_64` — the python.org runtime ships no 32-bit build).
1351
+ - **`[tool.kivy.android]` overlay** — `package` (applicationId), `version_code`
1352
+ (explicit or `"auto"` derived from `[project].version`), `min_sdk`/`target_sdk`/
1353
+ `compile_sdk`, `kivy_generation` (2 = Kivy 2.3.1, 3 = Kivy 3.0), `abis`, adaptive
1354
+ `icons`/`splash` (AndroidX SplashScreen), `permissions` (+ implied
1355
+ `<uses-feature>` synthesis), `services`/`activities`/`intent_filters`, the
1356
+ manifest passthrough (+ raw-XML), `native.aars`/`.jars` and Maven `gradle`
1357
+ dependencies, `include_files`, `src` (Java/Kotlin), `signing` (v1–v4 schemes),
1358
+ and `build_settings` (byte-compile/strip/R8/debug-symbols). Loader-validated
1359
+ (rules 1–21).
1360
+ - **kivyforge-owned bootstrap** — a generated `org.kivy.android.PythonActivity`
1361
+ (extends stock SDL2 `SDLActivity`), the pyjnius `NativeInvocationHandler`
1362
+ matched pair (with a hard `invoke0` contract gate), the Kivy-compat shims
1363
+ (`org.renpy.android.Hardware` + `mActivity`), an `SDL_main` native launcher
1364
+ (NDK-compiled per ABI), and a `sys.meta_path` finder over flattened extension
1365
+ `.so`s in `jniLibs/`. **pyjnius ships as a prebuilt Java-free wheel** (SDL-
1366
+ agnostic, `JNIEnv` resolved at runtime).
1367
+ - **Four artifact channels** — `android_*` wheels (PyPI / supplemental indexes /
1368
+ vendored `find_links`), the python.org runtime, `.aar`/`.jar` archives, and
1369
+ Maven coordinates (Gradle resolves; the graph is SHA-256-recorded in the lock).
1370
+ - **Mandatory signing** — debug builds use the auto-managed debug keystore;
1371
+ `package` requires a release keystore (env-var passwords, never in
1372
+ `pyproject.toml`), with a signing pre-flight and a release manifest-policy
1373
+ pre-flight (exported components, `debuggable`, placeholder package, …) that
1374
+ fail before Gradle.
1375
+ - **`kivyforge run --smoke`** — a generated instrumented contract test validates
1376
+ the extension-module finder + the pyjnius `invoke0` glue on a real
1377
+ device/emulator; the promotion mechanism for the compatibility matrix.
1378
+ - **`kivyforge doctor -p android`** — JDK/SDK/build-tools/NDK/emulator/adb, plus
1379
+ project checks (SDL↔Kivy, the pyjnius contract, a hermetic **16 KB
1380
+ ELF-alignment scanner**, ABI coverage, signing, lock-host reachability).
1381
+ - **Examples** — `hello-android` (Kivy 2.3.1 / SDL2), `hello-sdl3` (Kivy 3.0 /
1382
+ SDL3), `pyjnius-deviceinfo` (device info via pyjnius), and `qr-maven`
1383
+ (Google ZXing via the Maven channel + a Python-implements-Java `invoke0`
1384
+ round-trip), plus `examples/verify-android.ps1`.
1385
+ - **First-party wheels, no vendoring.** Kivy (2.3.1 and 3.0), pyjnius, and the
1386
+ matching SDL family are resolved from the
1387
+ [kivy-mobile-wheels](https://github.com/ElliotGarbus/kivy-mobile-wheels)
1388
+ index — a companion repo of first-party cibuildwheel cross-builds (official
1389
+ SDL sources, 16 KB page-aligned, sonames unchanged for `System.loadLibrary`)
1390
+ published as a static PEP 503 index. `hello-android` and `hello-sdl3` carry
1391
+ their locks committed as validation evidence; the rest resolve like any
1392
+ other dependency.
1393
+ - **SDL3 / Kivy 3.0 support.** `kivy_generation = 3` renders the SDL3 bootstrap template
1394
+ (`templates/sdl3/`) and pairs it with the matching wheel-repo glue;
1395
+ `check_sdl_glue_contract()` fails the build on any Java/`.so` version
1396
+ mismatch rather than the silent black-screen failure that mismatch would
1397
+ otherwise produce.
1398
+ - **Validated on real hardware.** `kivyforge run --smoke` passes on an x86_64
1399
+ emulator (API 31) **and** a Pixel 8a (Android 16 / API 36) for both the
1400
+ SDL2 and SDL3 stacks, with the app visually confirmed rendering on-device —
1401
+ see the [compatibility matrix](docs/design/platforms/android/08-compatibility-matrix.md).
1402
+
1403
+ ### Windows backend (onedir folder)
1404
+
1405
+ - **New `windows` target.** `kivyforge lock/build/run/package -p windows`
1406
+ resolves into `pylock.windows.toml`, bundles a relocatable
1407
+ [python-build-standalone](https://github.com/astral-sh/python-build-standalone)
1408
+ MSVC CPython plus `win_amd64` wheels, and produces a run-from-folder **`onedir`**:
1409
+ a windowed-subsystem launcher `.exe` beside the full runtime prefix, the app
1410
+ source, a generated bootstrap, and the native-binaries channel. amd64 only this
1411
+ phase; the config stays list-shaped for additive `win-arm64` later. Requires a
1412
+ Windows host (MSVC runtime + Windows-only rcedit/signtool).
1413
+ - **`[tool.kivy.windows]` overlay** — `app_id` (the AppUserModelID; hard
1414
+ constraints enforced at config time, PascalCase/period style a doctor WARN),
1415
+ `archs`, `python.version`, `icons.source`, optional `[signing]`
1416
+ (`thumbprint`/`timestamp_url`/`store_scope`), and the shared
1417
+ `extra_index_urls`/`find_links`/`exclude`.
1418
+ - **Prebuilt, reproducible launcher** — a single vendored windowed launcher
1419
+ `.exe` (built once from `launcher.c` with MSVC `/Brepro` + `/RELEASE` +
1420
+ `/EMITTOOLVERSIONINFO:NO`, SHA-256 pinned, byte-reproducibility gated in CI —
1421
+ the last flag drops the PE "rich header", whose serviced `cl`/`link` build
1422
+ stamp otherwise differs between runner images sharing one `VCTOOLSVERSION`) is
1423
+ parameterized per app only by its *resources* (icon + version) via the
1424
+ vendored `rcedit` — no per-build compiler.
1425
+ The launcher self-locates, sets the AppUserModelID, hands the console off on
1426
+ `run` while suppressing the flash on double-click, and spawns the bundled
1427
+ `python.exe` under a Job object.
1428
+ - **No-pip wheel staging** — locked wheels are unpacked into the runtime prefix
1429
+ by a deterministic wheel-scheme installer (routing `purelib`/`platlib`/`data`/
1430
+ `scripts`/`headers`), and `kivy_deps.*` DLLs land where the loader finds them.
1431
+ The `vcruntime140*.dll` are staged from the PBS prefix (empirically `msvcp140`
1432
+ is handled best-effort).
1433
+ - **Native-binaries channel + PE checks** — the shared staging helper gained
1434
+ Windows-facing guards (case-insensitive collision keys, reserved DOS
1435
+ device-name / alternate-data-stream rejection, exec-bit no-op) and a
1436
+ pure-Python PE machine-type reader so a wrong-architecture DLL fails the build
1437
+ clearly. The generated bootstrap registers `bin\` with `os.add_dll_directory`
1438
+ and prepends it to `PATH` (helpers run by name, DLLs load by name).
1439
+ - **Unsigned folder packaging** — `package -f folder` atomically copies the
1440
+ onedir into `dist\windows\<app>-<ver>-amd64\`, excluding build cache / VCS /
1441
+ editor droppings; the build tree stays the unsigned dev-run target.
1442
+ - **Optional Authenticode signing** — first-class but off by default. A new
1443
+ `Signer` protocol with `SigntoolSigner` (`signtool sign /sha1 <thumbprint>
1444
+ /fd SHA256 /tr <url> /td SHA256`, `/sm` for `store_scope=machine`, always
1445
+ timestamped) and `NullSigner`; identity is always a cert-store thumbprint,
1446
+ never a `.pfx`. A deterministic PEP 440 → four-part numeric `FILEVERSION`
1447
+ mapping feeds the version resource. Signing targets the `dist` copy only,
1448
+ after the resource patch.
1449
+ - **`kivyforge doctor -p windows`** — Windows host, long-path support,
1450
+ `app_id` style, arch coverage, app icon, native-binary sources/collisions/arch,
1451
+ resource assets, reachable hosts (incl. the signing timestamp server),
1452
+ `signtool` availability, and the signing certificate (in the configured
1453
+ `store_scope` store).
1454
+ - **Examples** — `desktop-viewer`, `dice-roller`, `notes`, and `hello-native`
1455
+ gained `[tool.kivy.windows]` overlays (hello-native adds a `greet.dll` +
1456
+ `roll.exe` native channel); `examples/verify-windows-examples.ps1` mirrors the
1457
+ desktop verifier's clean→lock→doctor→build→run→package→launch loop.
1458
+ - **CI** — `windows-latest` unit tests, a launcher reproducibility + vendored-asset
1459
+ gate, and a self-signed `signtool` sign→verify loop.
1460
+
1461
+ ### Linux backend (AppImage / AppDir)
1462
+
1463
+ - **New `linux` target.** `kivyforge lock/build/run/package -p linux` resolves
1464
+ into `pylock.linux.toml`, bundles a relocatable
1465
+ [python-build-standalone](https://github.com/astral-sh/python-build-standalone)
1466
+ gnu/glibc CPython plus manylinux wheels, and produces an
1467
+ [AppImage](https://appimage.org/) (the `package` default) with a
1468
+ run-from-folder **AppDir** as the substrate/fallback (`package -f folder`).
1469
+ x86_64 only this phase; the config stays list-shaped for additive `aarch64`
1470
+ later.
1471
+ - **`[tool.kivy.linux]` overlay** — `app_id` (reverse-DNS; names the generated
1472
+ `.desktop`, `Icon=`, and `StartupWMClass`), `archs`, optional `glibc_floor`,
1473
+ `python.version`, `icons.source`, `desktop.categories`, and the shared
1474
+ `extra_index_urls`/`find_links`/`exclude`. Invalid `app_id` characters are a
1475
+ fail-fast config error.
1476
+ - **manylinux resolution** — because pip does not expand the manylinux hierarchy
1477
+ from a single `--platform`, the resolver requests the full compatible tag
1478
+ ladder at/below the glibc floor in one invocation. The artifact's *effective*
1479
+ glibc floor = `max(runtime floor 2.17, highest locked wheel manylinux level)`.
1480
+ - **AppImage packaging** — a pinned static `appimagetool` + pinned type2
1481
+ static-FUSE runtime are fetched through the shared artifact cache; the shipped
1482
+ AppImage needs no host `libfuse2`, and `APPIMAGE_EXTRACT_AND_RUN=1` means the
1483
+ build host needs no FUSE either. A generated `AppRun` (POSIX shell) sets
1484
+ `PYTHONHOME`/`PYTHONPATH`/`SDL_VIDEO_*_WMCLASS` — no compiled launcher, no
1485
+ native build at package time.
1486
+ - **Generated desktop integration** — `.desktop` entry + hicolor icon set from
1487
+ `pyproject.toml` (Pillow for resize via the optional `kivyforge[linux]` extra;
1488
+ a default icon is generated with only the stdlib when no source is set).
1489
+ - **`kivyforge doctor -p linux`** — host libc (WARN on musl), `libGL`/`libEGL`
1490
+ via `ldconfig`, display session, glibc floor vs. runtime, manylinux arch
1491
+ coverage, app icon, generated `.desktop` validity (`desktop-file-validate`),
1492
+ and reachable hosts (lock + appimagetool/runtime assets).
1493
+ - **Host contract (documented, never vendored)** — the bundle relies on the host
1494
+ for glibc ≥ the effective floor, `libGL`/`libEGL`, and an X11/Wayland session.
1495
+ - **Examples** — `desktop-viewer`, `dice-roller`, and `notes` gained
1496
+ `[tool.kivy.linux]` overlays + committed `pylock.linux.toml`;
1497
+ `examples/run-examples.sh -p linux` builds and runs them.
1498
+ - **CI** — added an `ubuntu-latest` headless job (the cross-platform core now
1499
+ runs on both macOS and Linux hosts). Artifact cache respects
1500
+ `$XDG_CACHE_HOME` on Linux (`~/.cache/kivyforge`).
1501
+
1502
+ ## [v3.0.0](https://github.com/ElliotGarbus/kivyforge/tree/v3.0.0)
1503
+
1504
+ **Complete rewrite.** kivyforge is the successor to kivy-ios, python-for-android,
1505
+ and buildozer — a declarative, PEP 621-aligned build toolchain for Kivy apps
1506
+ aimed at every platform Kivy runs on. This first release implements the **iOS**
1507
+ target, built around pre-built Python.xcframeworks and pip-installable iOS wheels.
1508
+ The recipe-based `kivyforge build-recipe` workflow is gone; see the
1509
+ [design docs](docs/design/common/00-overview.md) and the updated README.
1510
+
1511
+ ### What's new in 3.0
1512
+
1513
+ - **Declarative config** — project settings live in `[tool.kivy]` /
1514
+ `[tool.kivy.ios]` sections of your app's `pyproject.toml`; no more
1515
+ `toolchain.spec` or `requirements.txt`. Config validation is strict and
1516
+ fail-fast: `[tool.kivy.ios.python].version` is required (no hidden default at
1517
+ lock time), native xcframework `source` paths may not escape the project,
1518
+ signing flags must be real booleans (a quoted `"false"` is rejected, not
1519
+ coerced to `true`), and `[tool.kivy.ios.xcode.build_settings]` values must be
1520
+ strings.
1521
+ - **Dependency locking** — `kivyforge lock` resolves pure-Python and iOS wheel
1522
+ dependencies and writes `pylock.ios.toml` (PEP 751-inspired).
1523
+ - **Python.xcframework** — Python is distributed as a pre-built xcframework;
1524
+ no source compilation required on the developer machine.
1525
+ - **iOS wheels** — third-party packages are distributed as pre-built
1526
+ `*-ios.whl` wheels; `kivyforge build` downloads and integrates them.
1527
+ - **Xcode project generation** — `kivyforge init` generates a complete
1528
+ `.xcodeproj` via `pbxproj`; `kivyforge open` launches Xcode.
1529
+ - **SDL3** — Kivy 3.0 moves to SDL3; the generated project and Info.plist
1530
+ are configured for the SDL3 UIScene lifecycle out of the box.
1531
+ - **Mobile window/display geometry via `kivy.mobile`** — DPI, scale, safe-area
1532
+ insets, and keyboard height are provided by Kivy core's `kivy.mobile` module
1533
+ (kivy/kivy#9331), shipped in the Kivy iOS wheel.
1534
+ - **Native iOS dependencies** — declare Swift Package Manager packages and
1535
+ native `.xcframework` archives under `[tool.kivy.ios.native]`. `kivyforge lock`
1536
+ pins SPM packages to a concrete revision and resolves each xcframework archive
1537
+ (by URL or repo-relative path) into a SHA-256 + enumerated slice list in
1538
+ `pylock.ios.toml`; `kivyforge build` fetches, verifies, and wires them into the
1539
+ Xcode project's Link / Embed phases per each entry's `link`/`embed` intent,
1540
+ pruning references for frameworks no longer present. When two sources stage the
1541
+ same `<name>.xcframework`, identical content (matching tree hash) is
1542
+ deduplicated silently and conflicting content fails the build, naming both
1543
+ providers and their hashes.
1544
+ - **Slim CLI** — `toolchain` now dispatches to `init`, `lock`, `build`, `run`,
1545
+ `open`, `upgrade`, `clean`, `status`, and `doctor`; legacy 2.x verbs print
1546
+ a migration pointer.
1547
+ - **Requires Python ≥ 3.13 and pip ≥ 24.3** on the developer machine (macOS
1548
+ only). pip 24.3 added PEP 730 iOS platform-tag matching, which `toolchain
1549
+ lock` relies on to resolve iOS wheels; `kivyforge doctor` flags older pip and
1550
+ `kivyforge lock` fails fast with an upgrade hint.
1551
+
1552
+ ---
1553
+
1554
+ > **Historical entries below this line describe kivy-ios 2.x** (the
1555
+ > recipe-based toolchain). They are preserved for reference but describe
1556
+ > a workflow that no longer exists in 3.0.
1557
+
1558
+ ---
1559
+
1560
+ ## [v2025.05.17](https://github.com/kivy/kivy-ios/tree/v2025.05.17)
1561
+
1562
+ [Full Changelog](https://github.com/kivy/kivy-ios/compare/v2024.03.17...v2025.05.17)
1563
+
1564
+ **Closed issues:**
1565
+
1566
+ - kivy fails to build on MacOS 15.4.1 \(-armv7 compiler failure\) [\#965](https://github.com/kivy/kivy-ios/issues/965)
1567
+ - push notification in ios? [\#964](https://github.com/kivy/kivy-ios/issues/964)
1568
+ - Libffi error while building python3 with Xcode 16.3 [\#963](https://github.com/kivy/kivy-ios/issues/963)
1569
+ - Fails to build on recipe for ios/src/ios.pyx [\#948](https://github.com/kivy/kivy-ios/issues/948)
1570
+ - target python needs to be patched [\#939](https://github.com/kivy/kivy-ios/issues/939)
1571
+ - Toolchain build kivy command is failing with Xcode 16 [\#936](https://github.com/kivy/kivy-ios/issues/936)
1572
+ - Toolchain does not build with Xcode 15.4 [\#929](https://github.com/kivy/kivy-ios/issues/929)
1573
+ - How is Accelerate not supported? [\#925](https://github.com/kivy/kivy-ios/issues/925)
1574
+ - M1 mac python3 build error [\#924](https://github.com/kivy/kivy-ios/issues/924)
1575
+ - Python error after building to iPhone Simulator [\#923](https://github.com/kivy/kivy-ios/issues/923)
1576
+ - Pillow not building [\#907](https://github.com/kivy/kivy-ios/issues/907)
1577
+ - Can't create a recipe [\#906](https://github.com/kivy/kivy-ios/issues/906)
1578
+ - Linker Command Failure Error While Building Python3 [\#905](https://github.com/kivy/kivy-ios/issues/905)
1579
+ - MacOS kivyforge build constantly failing \(I think due to C extension errors\) [\#901](https://github.com/kivy/kivy-ios/issues/901)
1580
+ - Unable to build with kivymd==2.0 [\#897](https://github.com/kivy/kivy-ios/issues/897)
1581
+ - Got dlopen error on Foundation [\#896](https://github.com/kivy/kivy-ios/issues/896)
1582
+ - Feature request: MatplotLib for iOS [\#712](https://github.com/kivy/kivy-ios/issues/712)
1583
+
1584
+ **Merged pull requests:**
1585
+
1586
+ - Use `-platform_version` flag during linking instead of the deprecated and now removed\) `-ios_simulator_version_min` [\#970](https://github.com/kivy/kivy-ios/pull/970) ([misl6](https://github.com/misl6))
1587
+ - Bump `libpng` version to `1.6.48` [\#967](https://github.com/kivy/kivy-ios/pull/967) ([misl6](https://github.com/misl6))
1588
+ - Disable iOS armv7 build for `libffi` [\#966](https://github.com/kivy/kivy-ios/pull/966) ([misl6](https://github.com/misl6))
1589
+ - Add `SDL3`, `SDL3_ttf`, `SDL3_mixer`, `SDL3_image` recipes for Kivy `3.0.0` [\#961](https://github.com/kivy/kivy-ios/pull/961) ([misl6](https://github.com/misl6))
1590
+ - chore\(deps\): update pypa/gh-action-pypi-publish action to v1.12.4 [\#958](https://github.com/kivy/kivy-ios/pull/958) ([renovate[bot]](https://github.com/apps/renovate))
1591
+ - Enhance Cython integration: Add support for `c++` mode, use hostpython3-provided Cython, allow pinning of specific Cython version in recipe [\#957](https://github.com/kivy/kivy-ios/pull/957) ([misl6](https://github.com/misl6))
1592
+ - Bump Kivy version to 2.3.1 [\#956](https://github.com/kivy/kivy-ios/pull/956) ([misl6](https://github.com/misl6))
1593
+ - chore\(deps\): update pypa/gh-action-pypi-publish action to v1.12.3 [\#952](https://github.com/kivy/kivy-ios/pull/952) ([renovate[bot]](https://github.com/apps/renovate))
1594
+ - chore\(deps\): update pypa/gh-action-pypi-publish action to v1.12.2 [\#942](https://github.com/kivy/kivy-ios/pull/942) ([renovate[bot]](https://github.com/apps/renovate))
1595
+ - Fix libb2 issue [\#940](https://github.com/kivy/kivy-ios/pull/940) ([tcaduser](https://github.com/tcaduser))
1596
+ - :construction\_worker: Fix broken setup workflow [\#938](https://github.com/kivy/kivy-ios/pull/938) ([AndreMiras](https://github.com/AndreMiras))
1597
+ - fix build for Xcode 16 [\#937](https://github.com/kivy/kivy-ios/pull/937) ([tcaduser](https://github.com/tcaduser))
1598
+ - Fix zbarlight recipe [\#932](https://github.com/kivy/kivy-ios/pull/932) ([Cheaterman](https://github.com/Cheaterman))
1599
+ - chore\(deps\): update actions/setup-python action to v5 [\#918](https://github.com/kivy/kivy-ios/pull/918) ([renovate[bot]](https://github.com/apps/renovate))
1600
+ - chore\(deps\): update pypa/gh-action-pypi-publish action to v1.10.2 [\#917](https://github.com/kivy/kivy-ios/pull/917) ([renovate[bot]](https://github.com/apps/renovate))
1601
+ - Bump minimum Python supported version to `3.8` [\#914](https://github.com/kivy/kivy-ios/pull/914) ([misl6](https://github.com/misl6))
1602
+ - chore: Configure Renovate [\#910](https://github.com/kivy/kivy-ios/pull/910) ([renovate[bot]](https://github.com/apps/renovate))
1603
+ - Sunset `apple-silicon-m1` self-hosted runner, as now is supported by Github Hosted runners via `macos-latest` tag. Use `macos-13` for runs on Intel macs [\#909](https://github.com/kivy/kivy-ios/pull/909) ([misl6](https://github.com/misl6))
1604
+ - \(`recipes/materialyoucolor`\): update to 2.0.9 [\#904](https://github.com/kivy/kivy-ios/pull/904) ([T-Dynamos](https://github.com/T-Dynamos))
1605
+
1606
+ ## [v2024.03.17](https://github.com/kivy/kivy-ios/tree/v2024.03.17)
1607
+
1608
+ [Full Changelog](https://github.com/kivy/kivy-ios/compare/v2023.08.24...v2024.03.17)
1609
+
1610
+ **Fixed bugs:**
1611
+
1612
+ - zbarlite recipe has hardcoded python version [\#677](https://github.com/kivy/kivy-ios/issues/677)
1613
+
1614
+ **Closed issues:**
1615
+
1616
+ - Materialyoucolor-python Recipe [\#895](https://github.com/kivy/kivy-ios/issues/895)
1617
+ - libffi recipe build hangs during configuration [\#889](https://github.com/kivy/kivy-ios/issues/889)
1618
+ - Can't Input text on IOS17.2 Simulator with Xcode 15.1 [\#888](https://github.com/kivy/kivy-ios/issues/888)
1619
+ - \[Request\]: Pypi packages [\#886](https://github.com/kivy/kivy-ios/issues/886)
1620
+ - Add pdf2docx recipe [\#883](https://github.com/kivy/kivy-ios/issues/883)
1621
+ - \[Question\] : Pygame and pyexpat ? [\#873](https://github.com/kivy/kivy-ios/issues/873)
1622
+ - Support mail address is broken [\#872](https://github.com/kivy/kivy-ios/issues/872)
1623
+ - Toolchain python version mismatch [\#869](https://github.com/kivy/kivy-ios/issues/869)
1624
+ - how to show ip camera footage [\#868](https://github.com/kivy/kivy-ios/issues/868)
1625
+ - Working app crash on iOS 17 [\#864](https://github.com/kivy/kivy-ios/issues/864)
1626
+ - Crash during background execution [\#862](https://github.com/kivy/kivy-ios/issues/862)
1627
+ - Python3 build fails with `unknown argument: '-fp-model'` [\#860](https://github.com/kivy/kivy-ios/issues/860)
1628
+ - issue creating recipe for kiwsolver [\#857](https://github.com/kivy/kivy-ios/issues/857)
1629
+ - App runs fine from XCode, but terminates with an error if installed through TestFlight [\#850](https://github.com/kivy/kivy-ios/issues/850)
1630
+ - ffmpeg related errors after adding this recipe to the project [\#849](https://github.com/kivy/kivy-ios/issues/849)
1631
+ - how do you init your custom c module at app startup? [\#848](https://github.com/kivy/kivy-ios/issues/848)
1632
+ - Replacement for pycrypto [\#843](https://github.com/kivy/kivy-ios/issues/843)
1633
+ - Xcode build fails with ModuleNotFoundError: No module named 'encodings' [\#842](https://github.com/kivy/kivy-ios/issues/842)
1634
+ - Invalid Signature when adding Python to iOS App Extension [\#826](https://github.com/kivy/kivy-ios/issues/826)
1635
+ - APP crashes easily [\#824](https://github.com/kivy/kivy-ios/issues/824)
1636
+ - when creating xcodeproj using kivy-ios, how to change the default bundleIdentifier [\#823](https://github.com/kivy/kivy-ios/issues/823)
1637
+ - kivyforge build: no matching architecture in universal wrapper [\#792](https://github.com/kivy/kivy-ios/issues/792)
1638
+ - Explanation to build recipe in iOS [\#776](https://github.com/kivy/kivy-ios/issues/776)
1639
+ - Support arm64 simulator on Apple Silicon hardware [\#751](https://github.com/kivy/kivy-ios/issues/751)
1640
+ - PyObjC import error [\#741](https://github.com/kivy/kivy-ios/issues/741)
1641
+ - App Store Connect Operation Error Invalid Bundle Structure - The binary file '\*myapp\*.app/lib/python3.9/site-packages/google/protobuf/pyext/\_message.cpython-39-darwin.so' is not permitted. [\#702](https://github.com/kivy/kivy-ios/issues/702)
1642
+ - libzbar recipe missing libiconv dependency [\#676](https://github.com/kivy/kivy-ios/issues/676)
1643
+ - Lib Not Found [\#674](https://github.com/kivy/kivy-ios/issues/674)
1644
+ - kivyforge build kivy Error [\#668](https://github.com/kivy/kivy-ios/issues/668)
1645
+ - leverage conda to create the host\* packages [\#655](https://github.com/kivy/kivy-ios/issues/655)
1646
+ - ImportError: dynamic module does not define module export function \(PyInit\_\_imaging\) [\#644](https://github.com/kivy/kivy-ios/issues/644)
1647
+ - kivy ios and boto3 [\#641](https://github.com/kivy/kivy-ios/issues/641)
1648
+ - Recipe for OpenCV [\#637](https://github.com/kivy/kivy-ios/issues/637)
1649
+ - Issues with using threads on an iOS device [\#609](https://github.com/kivy/kivy-ios/issues/609)
1650
+ - Xcode fails to build: Undefined symbols for architecture x86\_64 [\#607](https://github.com/kivy/kivy-ios/issues/607)
1651
+ - There is a memory leak in the program [\#419](https://github.com/kivy/kivy-ios/issues/419)
1652
+ - Include Unit tests and CI to test build for the toolchain [\#296](https://github.com/kivy/kivy-ios/issues/296)
1653
+
1654
+ **Merged pull requests:**
1655
+
1656
+ - :construction\_worker: Fix the rebuild recipe script [\#900](https://github.com/kivy/kivy-ios/pull/900) ([AndreMiras](https://github.com/AndreMiras))
1657
+ - recipes: add new `materialyoucolor` recipe [\#898](https://github.com/kivy/kivy-ios/pull/898) ([T-Dynamos](https://github.com/T-Dynamos))
1658
+ - Remove bitcode support, as is now deprecated by Apple [\#894](https://github.com/kivy/kivy-ios/pull/894) ([misl6](https://github.com/misl6))
1659
+ - Bump openssl version to `1.1.1w` [\#891](https://github.com/kivy/kivy-ios/pull/891) ([misl6](https://github.com/misl6))
1660
+ - Bump Kivy version to 2.3.0 [\#890](https://github.com/kivy/kivy-ios/pull/890) ([misl6](https://github.com/misl6))
1661
+ - Set `fetch-depth: 0` for updated recipes checkout and use `actions/checkout@v4` instead of `actions/checkout@v3` [\#884](https://github.com/kivy/kivy-ios/pull/884) ([misl6](https://github.com/misl6))
1662
+ - Update sdl2 deps to reflect the same targeted in kivy/kivy [\#881](https://github.com/kivy/kivy-ios/pull/881) ([misl6](https://github.com/misl6))
1663
+ - Make doc structure consistent and up-to-date [\#879](https://github.com/kivy/kivy-ios/pull/879) ([Julian-O](https://github.com/Julian-O))
1664
+ - Create no-response [\#878](https://github.com/kivy/kivy-ios/pull/878) ([Julian-O](https://github.com/Julian-O))
1665
+ - Support Section Updated issue \#872 resolved [\#876](https://github.com/kivy/kivy-ios/pull/876) ([seharbat00l](https://github.com/seharbat00l))
1666
+ - Install kivy-ios via pip during tests, so dependencies are automatically managed [\#871](https://github.com/kivy/kivy-ios/pull/871) ([misl6](https://github.com/misl6))
1667
+ - Update `python3` recipe to `3.11.6` [\#870](https://github.com/kivy/kivy-ios/pull/870) ([misl6](https://github.com/misl6))
1668
+ - Do not use full path for system libraries and frameworks in `.xcodeproj` [\#867](https://github.com/kivy/kivy-ios/pull/867) ([misl6](https://github.com/misl6))
1669
+ - Fix for upstream issues with compiler path [\#866](https://github.com/kivy/kivy-ios/pull/866) ([tcaduser](https://github.com/tcaduser))
1670
+ - update to matplotlib 3.7.2 [\#861](https://github.com/kivy/kivy-ios/pull/861) ([tcaduser](https://github.com/tcaduser))
1671
+ - update for recent iOS platform changes [\#859](https://github.com/kivy/kivy-ios/pull/859) ([tcaduser](https://github.com/tcaduser))
1672
+ - matplotlib recipe [\#858](https://github.com/kivy/kivy-ios/pull/858) ([tcaduser](https://github.com/tcaduser))
1673
+ - Bump `numpy` version to `1.24.4` [\#856](https://github.com/kivy/kivy-ios/pull/856) ([misl6](https://github.com/misl6))
1674
+ - Support ARM64 Simulator + Introduce build platform concept + Introduce `xcframework` [\#778](https://github.com/kivy/kivy-ios/pull/778) ([misl6](https://github.com/misl6))
1675
+
1676
+
1677
+ ## [v2023.08.24](https://github.com/kivy/kivy-ios/tree/v2023.08.24)
1678
+
1679
+ [Full Changelog](https://github.com/kivy/kivy-ios/compare/v2023.05.21...v2023.08.24)
1680
+
1681
+ **Fixed bugs:**
1682
+
1683
+ - ld: 407 duplicate symbols for architecture arm64 [\#787](https://github.com/kivy/kivy-ios/issues/787)
1684
+
1685
+ **Closed issues:**
1686
+
1687
+ - please delete [\#846](https://github.com/kivy/kivy-ios/issues/846)
1688
+ - Label and MDLabel don't work correctly on iOS [\#845](https://github.com/kivy/kivy-ios/issues/845)
1689
+ - ImportError: dynamic module does not define module export function \(PyInit\_\_bcrypt\) [\#841](https://github.com/kivy/kivy-ios/issues/841)
1690
+ - Build failure [\#838](https://github.com/kivy/kivy-ios/issues/838)
1691
+ - Custom recipes just like p4a [\#837](https://github.com/kivy/kivy-ios/issues/837)
1692
+ - pandas recipe [\#836](https://github.com/kivy/kivy-ios/issues/836)
1693
+ - Build numpy: '\['/kivy/dist/hostpython3/bin/python', '-m', 'cython', '-3', '--fast-fail', '-o', '\_philox.c', '\_philox.pyx'\]' returned non-zero exit status 1.' [\#835](https://github.com/kivy/kivy-ios/issues/835)
1694
+ - ios.c not found when building ios for kivy [\#833](https://github.com/kivy/kivy-ios/issues/833)
1695
+ - Imvaild symlink [\#825](https://github.com/kivy/kivy-ios/issues/825)
1696
+ - dynamic module does not define module export function \(PyInit\_\_multiarray\_umath\) [\#822](https://github.com/kivy/kivy-ios/issues/822)
1697
+ - Toolchain build openssl not working [\#819](https://github.com/kivy/kivy-ios/issues/819)
1698
+ - OSError: codec configuration error when reading image file [\#818](https://github.com/kivy/kivy-ios/issues/818)
1699
+ - Command PhaseScriptExecution failed with a nonzero exit code [\#817](https://github.com/kivy/kivy-ios/issues/817)
1700
+ - We discovered that the content didn’t load after launched. [\#816](https://github.com/kivy/kivy-ios/issues/816)
1701
+ - Asset validation failed Invalid bundle structure. The “soccer.app/lib/python3.10/site-packages/charset\_normalizer/md.cpython-310-darwin.so” binary file is not permitted. [\#815](https://github.com/kivy/kivy-ios/issues/815)
1702
+ - Asset validation failed Invalid Bundle Structure for libnpyrandom.a and libnpymath.a [\#814](https://github.com/kivy/kivy-ios/issues/814)
1703
+ - kivy-ios Not found '\_SHA256.so' [\#813](https://github.com/kivy/kivy-ios/issues/813)
1704
+ - The toggling of the 'readonly' attribute \(True/False\) for the MDTextField is not functioning as expected in the xcode build [\#811](https://github.com/kivy/kivy-ios/issues/811)
1705
+ - libpng recipe won't build [\#808](https://github.com/kivy/kivy-ios/issues/808)
1706
+ - build error in Python3.8 [\#796](https://github.com/kivy/kivy-ios/issues/796)
1707
+
1708
+ **Merged pull requests:**
1709
+
1710
+ - Use a pinned version of `Cython` for now, as most of the recipes are incompatible with `Cython==3.x.x` [\#844](https://github.com/kivy/kivy-ios/pull/844) ([misl6](https://github.com/misl6))
1711
+ - Remove Unused Dependency: `requests` [\#840](https://github.com/kivy/kivy-ios/pull/840) ([gdrosos](https://github.com/gdrosos))
1712
+ - Fix download from `sourceforge` \(and possibly many others\) [\#830](https://github.com/kivy/kivy-ios/pull/830) ([misl6](https://github.com/misl6))
1713
+ - Now Github Actions provides `python3` via `setup-python` also for Apple Silicon macs [\#829](https://github.com/kivy/kivy-ios/pull/829) ([misl6](https://github.com/misl6))
1714
+ - Bump Kivy version to 2.2.1 [\#828](https://github.com/kivy/kivy-ios/pull/828) ([misl6](https://github.com/misl6))
1715
+ - Update `libpng` recipe and build `SDL2_ttf` vendored `freetype` with png support, so can render colored emoji [\#827](https://github.com/kivy/kivy-ios/pull/827) ([misl6](https://github.com/misl6))
1716
+ - SDL\_ttf: Hide internal symbols via single-object prelink [\#820](https://github.com/kivy/kivy-ios/pull/820) ([misl6](https://github.com/misl6))
1717
+ - Update zbarlight recipe to 3.0, refactor [\#805](https://github.com/kivy/kivy-ios/pull/805) ([Cheaterman](https://github.com/Cheaterman))
1718
+ - Refactor biglink ; add extra assertions to help debug failures [\#804](https://github.com/kivy/kivy-ios/pull/804) ([Cheaterman](https://github.com/Cheaterman))
1719
+
1720
+
1721
+ ## [v2023.05.21](https://github.com/kivy/kivy-ios/tree/v2023.05.21)
1722
+
1723
+ [Full Changelog](https://github.com/kivy/kivy-ios/compare/v2023.01.29...v2023.05.21)
1724
+
1725
+ **Closed issues:**
1726
+
1727
+ - Issue adding Pillow to Kivy-ios build [\#807](https://github.com/kivy/kivy-ios/issues/807)
1728
+ - I have created and app using kivy. it works in python through VS code but when I run through Xcode it gets no module named "application name" in main.py, line number 4 error and close the app in simulator. I tried all the ways in previous discussions but still not working. is there any other way I can try? [\#800](https://github.com/kivy/kivy-ios/issues/800)
1729
+ - Kivy ios save an screen as an image to the users ios photos [\#799](https://github.com/kivy/kivy-ios/issues/799)
1730
+ - Command PhaseScriptExecution failed with a nonzero exit code [\#793](https://github.com/kivy/kivy-ios/issues/793)
1731
+ - ImportError: PyInit\_interval [\#788](https://github.com/kivy/kivy-ios/issues/788)
1732
+ - Recipe for the cryptography module [\#786](https://github.com/kivy/kivy-ios/issues/786)
1733
+ - Pyaudio [\#785](https://github.com/kivy/kivy-ios/issues/785)
1734
+ - Check \#783 [\#784](https://github.com/kivy/kivy-ios/issues/784)
1735
+ - Command PhaseScriptExecution failed with a nonzero exit code [\#783](https://github.com/kivy/kivy-ios/issues/783)
1736
+ - Cocoapods import not found when kivy is installed [\#777](https://github.com/kivy/kivy-ios/issues/777)
1737
+ - sh.CommandNotFound: /Users/suhaan/Documents/weatherappkivy/dist/hostpython3/bin/pip3 [\#775](https://github.com/kivy/kivy-ios/issues/775)
1738
+ - check \#773 issue [\#774](https://github.com/kivy/kivy-ios/issues/774)
1739
+ - Asset validation failed Invalid bundle structure. The “theweatherreporterapp.app/lib/python3.9/site-packages/charset\_normalizer/md\_\_mypyc.cpython-39-darwin.so” binary file is not permitted. Your app cannot contain standalone executables or libraries, other than a valid CFBundleExecutable of supported bundles. For details, visit: https://developer.apple.com/documentation/bundleresources/placing\_content\_in\_a\_bundle \(ID: eb2a7a62-515c-459b-a222-5330e609551d\) [\#773](https://github.com/kivy/kivy-ios/issues/773)
1740
+ - dynamic module does not define module export function \(PyInit\_md\) error [\#772](https://github.com/kivy/kivy-ios/issues/772)
1741
+ - Toolchain 407 duplicate error of arm64 [\#771](https://github.com/kivy/kivy-ios/issues/771)
1742
+ - bash: toolchain: command not found [\#770](https://github.com/kivy/kivy-ios/issues/770)
1743
+ - when running kivyforge build python3 kivy pillow with arch arm64 with apple sicion getting list index out of range [\#769](https://github.com/kivy/kivy-ios/issues/769)
1744
+ - Error compiling SDL\_Image [\#763](https://github.com/kivy/kivy-ios/issues/763)
1745
+ - ImportError: dynamic module does not define module export function \(PyInit\_PIL\_\_imaging\) [\#711](https://github.com/kivy/kivy-ios/issues/711)
1746
+ - Build python3 with mmap module [\#659](https://github.com/kivy/kivy-ios/issues/659)
1747
+
1748
+ **Merged pull requests:**
1749
+
1750
+ - Fix AnyIO \(and asks\) support [\#803](https://github.com/kivy/kivy-ios/pull/803) ([Cheaterman](https://github.com/Cheaterman))
1751
+ - Update Kivy recipe for 2.2.0 [\#802](https://github.com/kivy/kivy-ios/pull/802) ([misl6](https://github.com/misl6))
1752
+ - Use `--no-deps` and `--platform` during install of recipe python deps [\#801](https://github.com/kivy/kivy-ios/pull/801) ([misl6](https://github.com/misl6))
1753
+ - Fixes crash on ios.get\_safe\_area\(\) in iOS 16 [\#790](https://github.com/kivy/kivy-ios/pull/790) ([tito](https://github.com/tito))
1754
+ - Update bridge.m/h to make plyer works with severals implementation [\#789](https://github.com/kivy/kivy-ios/pull/789) ([tito](https://github.com/tito))
1755
+ - Bump `numpy` version to `1.24.2` \( and fix the build on Python 3.10 ✅ \) [\#780](https://github.com/kivy/kivy-ios/pull/780) ([misl6](https://github.com/misl6))
1756
+ - Disable SDL2 hidapi in order to avoid dependency on `CoreBluetooth` [\#779](https://github.com/kivy/kivy-ios/pull/779) ([misl6](https://github.com/misl6))
1757
+ - 🎉 Python 3.10 support [\#768](https://github.com/kivy/kivy-ios/pull/768) ([misl6](https://github.com/misl6))
1758
+ - Upgrade more GitHub Actions plus Python 3.11.1 and Cython 0.29.33 [\#767](https://github.com/kivy/kivy-ios/pull/767) ([cclauss](https://github.com/cclauss))
1759
+ - Upgrade GitHub Actions [\#765](https://github.com/kivy/kivy-ios/pull/765) ([cclauss](https://github.com/cclauss))
1760
+ - Update required Xcode version to 13 [\#764](https://github.com/kivy/kivy-ios/pull/764) ([misl6](https://github.com/misl6))
1761
+ - Update ffmpeg/ffpyplayer versions [\#716](https://github.com/kivy/kivy-ios/pull/716) ([tito](https://github.com/tito))
1762
+
1763
+
1764
+ ## [v2023.01.29](https://github.com/kivy/kivy-ios/tree/v2023.01.29)
1765
+
1766
+ [Full Changelog](https://github.com/kivy/kivy-ios/compare/v2022.07.19...v2023.01.29)
1767
+
1768
+ **Closed issues:**
1769
+
1770
+ - Unknown class `<BoxShadow>` [\#758](https://github.com/kivy/kivy-ios/issues/758)
1771
+ - toolchain pip3 install pycryptodome error [\#755](https://github.com/kivy/kivy-ios/issues/755)
1772
+ - Stuck between two error codes: ImportError...\(PyInit\_\_imaging\) and 407 duplicate symbols [\#752](https://github.com/kivy/kivy-ios/issues/752)
1773
+ - Toolchain Build error - commandnotfound python [\#748](https://github.com/kivy/kivy-ios/issues/748)
1774
+ - No module named 'xxx' [\#744](https://github.com/kivy/kivy-ios/issues/744)
1775
+ - dynamic module does not define module export function \(PyInit\_\_sqlite3\) [\#743](https://github.com/kivy/kivy-ios/issues/743)
1776
+ - \[BUG\] Kivy Ios on mac os monterey arm64 simulator [\#740](https://github.com/kivy/kivy-ios/issues/740)
1777
+ - PhaseScriptExecution failed when hitting Play in Xcode [\#739](https://github.com/kivy/kivy-ios/issues/739)
1778
+ - toolchain.py build python3 openssl kivy not completing after upgrading macOS Monterey 12.5 [\#738](https://github.com/kivy/kivy-ios/issues/738)
1779
+ - Proposal of versioning numbering method change for the next release [\#729](https://github.com/kivy/kivy-ios/issues/729)
1780
+ - xcode archive failure- missing signing identifier ... site-packages/google/...\_api\_implementation.cpython-39-darwin.so [\#697](https://github.com/kivy/kivy-ios/issues/697)
1781
+
1782
+ **Merged pull requests:**
1783
+
1784
+ - Update pbxproj pinned version in requirements.txt [\#757](https://github.com/kivy/kivy-ios/pull/757) ([misl6](https://github.com/misl6))
1785
+ - Add default Launch Screen storyboard [\#756](https://github.com/kivy/kivy-ios/pull/756) ([misl6](https://github.com/misl6))
1786
+ - Flake8 does not support inline comments for any of the keys [\#754](https://github.com/kivy/kivy-ios/pull/754) ([misl6](https://github.com/misl6))
1787
+ - Use Python 3.10 for tests [\#750](https://github.com/kivy/kivy-ios/pull/750) ([misl6](https://github.com/misl6))
1788
+ - Update SDL2, SDL2\_ttf, SDL2\_mixer, SDL2\_image to latest releases [\#749](https://github.com/kivy/kivy-ios/pull/749) ([misl6](https://github.com/misl6))
1789
+ - :rotating\_light: Minor linting fixes/updates [\#747](https://github.com/kivy/kivy-ios/pull/747) ([AndreMiras](https://github.com/AndreMiras))
1790
+ - Fixes some E275 - assert is a keyword [\#746](https://github.com/kivy/kivy-ios/pull/746) ([misl6](https://github.com/misl6))
1791
+ - Use `sys.executable` instead of `sh.python` [\#745](https://github.com/kivy/kivy-ios/pull/745) ([misl6](https://github.com/misl6))
1792
+ - Multiple fixes to README [\#737](https://github.com/kivy/kivy-ios/pull/737) ([rshah713](https://github.com/rshah713))
1793
+ - Fix typo in README [\#736](https://github.com/kivy/kivy-ios/pull/736) ([rshah713](https://github.com/rshah713))
1794
+ - Disable configuration of i386-Simulator for libffi [\#761](https://github.com/kivy/kivy-ios/pull/761) ([misl6](https://github.com/misl6)
1795
+
1796
+ ## [2022.07.19] - 2022-07-19
1797
+
1798
+ ## Added
1799
+ - Added py3dns recipe [\#728](https://github.com/kivy/kivy-ios/pull/728) ([Neizvestnyj](https://github.com/Neizvestnyj))
1800
+ - Ignore egg-info in git [\#718](https://github.com/kivy/kivy-ios/pull/718) ([tito](https://github.com/tito))
1801
+ - Bump Kivy recipe to a commit that includes latest camera API enhancements [\#700](https://github.com/kivy/kivy-ios/pull/700) ([RobertFlatt](https://github.com/RobertFlatt))
1802
+ - Add support-requests v2 [\#689](https://github.com/kivy/kivy-ios/pull/689) ([misl6](https://github.com/misl6))
1803
+
1804
+ ## Fixed
1805
+ - Updated shebangs to target python3. Bumped libffi version to 3.4.2 [\#688](https://github.com/kivy/kivy-ios/pull/688) ([misl6](https://github.com/misl6))
1806
+ - Fixes libffi 3.4.2 not linking correctly (missing symbols) on iOS Simulator [\#695](https://github.com/kivy/kivy-ios/pull/695) ([misl6](https://github.com/misl6))
1807
+ - Update dpi for latest iPhone models [\#707](https://github.com/kivy/kivy-ios/pull/707) ([akshayaurora](https://github.com/akshayaurora))
1808
+ - Our self-hosted Apple Silicon runner now has been migrated to actions/runner v2.292.0 which now supports arm64 natively [\#710](https://github.com/kivy/kivy-ios/pull/710) ([misl6](https://github.com/misl6))
1809
+ - Update xcassets to include mandatory icons in latest xcode [\#717](https://github.com/kivy/kivy-ios/pull/717) ([tito](https://github.com/tito))
1810
+ - Bump cookiecutter from 1.7.2 to 2.1.1 [\#714](https://github.com/kivy/kivy-ios/pull/714) ([dependabot](https://github.com/dependabot))
1811
+ - Use shutil.which instead of sh.which [\#735](https://github.com/kivy/kivy-ios/pull/735) ([misl6](https://github.com/misl6))
1812
+
1813
+ ## [2022.07.19] - 2022-07-19
1814
+
1815
+ ## Added
1816
+ - Added py3dns recipe [\#728](https://github.com/kivy/kivy-ios/pull/728) ([Neizvestnyj](https://github.com/Neizvestnyj))
1817
+ - Ignore egg-info in git [\#718](https://github.com/kivy/kivy-ios/pull/718) ([tito](https://github.com/tito))
1818
+ - Bump Kivy recipe to a commit that includes latest camera API enhancements [\#700](https://github.com/kivy/kivy-ios/pull/700) ([RobertFlatt](https://github.com/RobertFlatt))
1819
+ - Add support-requests v2 [\#689](https://github.com/kivy/kivy-ios/pull/689) ([misl6](https://github.com/misl6))
1820
+
1821
+ ## Fixed
1822
+ - Updated shebangs to target python3. Bumped libffi version to 3.4.2 [\#688](https://github.com/kivy/kivy-ios/pull/688) ([misl6](https://github.com/misl6))
1823
+ - Fixes libffi 3.4.2 not linking correctly (missing symbols) on iOS Simulator [\#695](https://github.com/kivy/kivy-ios/pull/695) ([misl6](https://github.com/misl6))
1824
+ - Update dpi for latest iPhone models [\#707](https://github.com/kivy/kivy-ios/pull/707) ([akshayaurora](https://github.com/akshayaurora))
1825
+ - Our self-hosted Apple Silicon runner now has been migrated to actions/runner v2.292.0 which now supports arm64 natively [\#710](https://github.com/kivy/kivy-ios/pull/710) ([misl6](https://github.com/misl6))
1826
+ - Update xcassets to include mandatory icons in latest xcode [\#717](https://github.com/kivy/kivy-ios/pull/717) ([tito](https://github.com/tito))
1827
+ - Bump cookiecutter from 1.7.2 to 2.1.1 [\#714](https://github.com/kivy/kivy-ios/pull/714) ([dependabot](https://github.com/dependabot))
1828
+ - Use shutil.which instead of sh.which [\#735](https://github.com/kivy/kivy-ios/pull/735) ([misl6](https://github.com/misl6))
1829
+
1830
+ ## [1.3.0] - 2022-03-13
1831
+
1832
+ ### Added
1833
+ - Add native support for Apple Silicon [\#660](https://github.com/kivy/kivy-ios/pull/660) ([misl6](https://github.com/misl6))
1834
+ - Makes \_bz2 module available [\#658](https://github.com/kivy/kivy-ios/pull/658) ([misl6](https://github.com/misl6))
1835
+ - enable sdl2 image provider to allow image to be saved from widget [\#656](https://github.com/kivy/kivy-ios/pull/656) ([brentpicasso](https://github.com/brentpicasso))
1836
+ - Add MANIFEST.in [\#651](https://github.com/kivy/kivy-ios/pull/651) ([misl6](https://github.com/misl6))
1837
+ - Add official OSI name in the license metadata [\#639](https://github.com/kivy/kivy-ios/pull/639) ([ecederstrand](https://github.com/ecederstrand))
1838
+ - Enables buildozer to automatically install dependencies [\#638](https://github.com/kivy/kivy-ios/pull/638) ([meow464](https://github.com/meow464))
1839
+ - Add bitcode support [\#605](https://github.com/kivy/kivy-ios/pull/605) ([kewlbear](https://github.com/kewlbear))
1840
+ - Add the ability to clean a custom recipe, use the custom recipe instead of the bundled one, if available. [\#602](https://github.com/kivy/kivy-ios/pull/602) ([misl6](https://github.com/misl6))
1841
+ - Add an error to FAQ [\#586](https://github.com/kivy/kivy-ios/pull/586) ([mvasilkov](https://github.com/mvasilkov))
1842
+
1843
+ ### Removed
1844
+ - Remove NO\_CONFIG and NO\_FILE\_LOG [\#670](https://github.com/kivy/kivy-ios/pull/670) ([akshayaurora](https://github.com/akshayaurora))
1845
+ - Remove i386 and armv7 references from docs and code. Both are unsupported since a while. [\#610](https://github.com/kivy/kivy-ios/pull/610) ([misl6](https://github.com/misl6))
1846
+
1847
+ ### Fixed
1848
+ - Bump Kivy version to 2.1.0 [\#679](https://github.com/kivy/kivy-ios/pull/679) ([misl6](https://github.com/misl6))
1849
+ - CI: Use a Kivy-ios installation for tests, instead of the legacy toolchain.py [\#653](https://github.com/kivy/kivy-ios/pull/653) ([misl6](https://github.com/misl6))
1850
+ - Fix outdated freetype url [\#632](https://github.com/kivy/kivy-ios/pull/632) ([misl6](https://github.com/misl6))
1851
+ - Bump sdl2\_ttf to 2.0.15 to improve compatibility with kivymd [\#624](https://github.com/kivy/kivy-ios/pull/624) ([brentpicasso](https://github.com/brentpicasso))
1852
+ - add leading whitespace for include file [\#623](https://github.com/kivy/kivy-ios/pull/623) ([brentpicasso](https://github.com/brentpicasso))
1853
+ - fix icon generation [\#620](https://github.com/kivy/kivy-ios/pull/620) ([akshayaurora](https://github.com/akshayaurora))
1854
+ - Switch to iOS 9.0 where applicable [\#611](https://github.com/kivy/kivy-ios/pull/611) ([misl6](https://github.com/misl6))
1855
+ - Pillow recipe rework + upgrade to version 8.2.0 [\#606](https://github.com/kivy/kivy-ios/pull/606) ([misl6](https://github.com/misl6))
1856
+ - Update numpy to version 1.20.2 [\#604](https://github.com/kivy/kivy-ios/pull/604) ([misl6](https://github.com/misl6))
1857
+ - Upgrade python version to 3.9.2 [\#601](https://github.com/kivy/kivy-ios/pull/601) ([misl6](https://github.com/misl6))
1858
+
1859
+ ## [1.2.1] - 2021-01-26
1860
+ ### Fixed
1861
+ - Fixes hostpython3 recipe on MacOS 11.1 BigSur [\#581](https://github.com/kivy/kivy-ios/issues/581) ([misl6](https://github.com/misl6))
1862
+ - Fixes iOS Simulator on latest Xcode [\#571](https://github.com/kivy/kivy-ios/issues/571) ([misl6](https://github.com/misl6))
1863
+ - Fixes Pillow build on Xcode 12.2 [\#579](https://github.com/kivy/kivy-ios/issues/579) ([misl6](https://github.com/misl6))
1864
+ - Cookiecutter: Fixes header and library search paths on Release [\#582](https://github.com/kivy/kivy-ios/issues/582) ([misl6](https://github.com/misl6))
1865
+
1866
+ ## [1.2.0] - 2020-12-26
1867
+ ### Added
1868
+ - :books: Advise on using a venv [\#495](https://github.com/kivy/kivy-ios/issues/495) ([AndreMiras](https://github.com/AndreMiras))
1869
+ - Add custom recipes [\#417](https://github.com/kivy/kivy-ios/issues/417) ([misl6](https://github.com/misl6))
1870
+ - Add feature request template [\#557](https://github.com/kivy/kivy-ios/issues/557) ([Zen-CODE](https://github.com/Zen-CODE))
1871
+ - Add instruction for cleaning cache and the build directory [\#558](https://github.com/kivy/kivy-ios/issues/558) ([Zen-CODE](https://github.com/Zen-CODE))
1872
+
1873
+ ### Removed
1874
+ - Remove distribute recipe [\#507](https://github.com/kivy/kivy-ios/issues/507) ([Zen-CODE](https://github.com/Zen-CODE))
1875
+ - Remove PY2 legacy blocks from coockiecutter main.m [\#522](https://github.com/kivy/kivy-ios/issues/522) ([Zen-CODE](https://github.com/Zen-CODE))
1876
+ - Remove outdated pil and pkgresources recipes [\#524](https://github.com/kivy/kivy-ios/issues/524) ([Zen-CODE](https://github.com/Zen-CODE))
1877
+ - Removed broken packages listing for non-existing packages [\#525](https://github.com/kivy/kivy-ios/issues/525) ([Zen-CODE](https://github.com/Zen-CODE))
1878
+
1879
+ ### Fixed
1880
+ - :bug: fixes flake8 errors post update [\#496](https://github.com/kivy/kivy-ios/issues/496) ([AndreMiras](https://github.com/AndreMiras))
1881
+ - Updates netifaces recipe, leverages `python_depends` [\#490](https://github.com/kivy/kivy-ios/issues/490) ([AndreMiras](https://github.com/AndreMiras))
1882
+ - Fix pillow recipe [\#498](https://github.com/kivy/kivy-ios/issues/498) ([Zen-CODE](https://github.com/Zen-CODE))
1883
+ - Fix/pillow [\#500](https://github.com/kivy/kivy-ios/issues/500) ([Zen-CODE](https://github.com/Zen-CODE))
1884
+ - Fix wekzeug recipe [\#501](https://github.com/kivy/kivy-ios/issues/501) ([Zen-CODE](https://github.com/Zen-CODE))
1885
+ - Fix markupsafe recipe [\#505](https://github.com/kivy/kivy-ios/issues/505) ([Zen-CODE](https://github.com/Zen-CODE))
1886
+ - Fix jinja2 recipe, remove from broken list [\#508](https://github.com/kivy/kivy-ios/issues/508) ([Zen-CODE](https://github.com/Zen-CODE))
1887
+ - Fix werkzeug recipe [\#509](https://github.com/kivy/kivy-ios/issues/509) ([Zen-CODE](https://github.com/Zen-CODE))
1888
+ - Pin flask version and dependencies [\#510](https://github.com/kivy/kivy-ios/issues/510) ([Zen-CODE](https://github.com/Zen-CODE))
1889
+ - :bug: Updates libffi download link [\#516](https://github.com/kivy/kivy-ios/issues/516) ([AndreMiras](https://github.com/AndreMiras))
1890
+ - Remove --ignore-installed [\#521](https://github.com/kivy/kivy-ios/issues/521) ([misl6](https://github.com/misl6))
1891
+ - Remove compile cruft after build [\#523](https://github.com/kivy/kivy-ios/issues/523) ([Zen-CODE](https://github.com/Zen-CODE))
1892
+ - Move Cython requirement into requirements.txt [\#531](https://github.com/kivy/kivy-ios/issues/531) ([Zen-CODE](https://github.com/Zen-CODE))
1893
+ - Fix/host setuptools3 [\#533](https://github.com/kivy/kivy-ios/issues/533) ([Zen-CODE](https://github.com/Zen-CODE))
1894
+ - Fixes CI [\#569](https://github.com/kivy/kivy-ios/issues/569) ([misl6](https://github.com/misl6))
1895
+ - Fix build on Xcode 12.2 [\#568](https://github.com/kivy/kivy-ios/issues/568) ([misl6](https://github.com/misl6))
1896
+ - Update openssl and ffmpeg version to fix build issues [\#562](https://github.com/kivy/kivy-ios/issues/562) ([Zen-CODE](https://github.com/Zen-CODE))
1897
+ - Update kivy to a post 2.0.0 version [\#575](https://github.com/kivy/kivy-ios/issues/575) ([misl6](https://github.com/misl6))
1898
+
1899
+ ## [1.1.2] - 2020-05-11
1900
+ ### Fixed
1901
+ - Fixes (venv build) reference to SDL\_main.h [\#493](https://github.com/kivy/kivy-ios/issues/493) ([AndreMiras](https://github.com/AndreMiras))
1902
+
1903
+ ## [1.1.1] - 2020-05-11
1904
+ ### Added
1905
+ - Add python depends [\#455](https://github.com/kivy/kivy-ios/issues/455) ([misl6](https://github.com/misl6))
1906
+
1907
+ ### Removed
1908
+ - Removed Python 2 support [\#482](https://github.com/kivy/kivy-ios/issues/482) ([AndreMiras](https://github.com/AndreMiras))
1909
+
1910
+ ### Fixed
1911
+ - Adds initial\_working\_directory [\#489](https://github.com/kivy/kivy-ios/issues/489) ([misl6](https://github.com/misl6))
1912
+ - Adds netifaces recipe, closes #239 [\#488](https://github.com/kivy/kivy-ios/issues/488) ([AndreMiras](https://github.com/AndreMiras))
1913
+ - Uses contextlib.suppress to ignore exceptions [\#487](https://github.com/kivy/kivy-ios/issues/487) ([AndreMiras](https://github.com/AndreMiras))
1914
+ - DRY via the find\_xcodeproj() helper method [\#486](https://github.com/kivy/kivy-ios/issues/486) ([AndreMiras](https://github.com/AndreMiras))
1915
+ - Uses cd context manager in Python3Recipe.reduce\_python() [\#485](https://github.com/kivy/kivy-ios/issues/485) ([AndreMiras](https://github.com/AndreMiras))
1916
+ - Uses Python 3 syntax [\#484](https://github.com/kivy/kivy-ios/issues/484) ([AndreMiras](https://github.com/AndreMiras))
1917
+ - Also lints the tools/ folder [\#483](https://github.com/kivy/kivy-ios/issues/483) ([AndreMiras](https://github.com/AndreMiras))
1918
+ - Migrates libffi build to Python 3 [\#481](https://github.com/kivy/kivy-ios/issues/481) ([AndreMiras](https://github.com/AndreMiras))
1919
+ - Uses a couple of syntax shortcuts [\#479](https://github.com/kivy/kivy-ios/issues/479) ([AndreMiras](https://github.com/AndreMiras))
1920
+ - Takes ToolchainCL definition outside the main [\#478](https://github.com/kivy/kivy-ios/issues/478) ([AndreMiras](https://github.com/AndreMiras))
1921
+
1922
+ ## [1.1.0] - 2020-05-05
1923
+ ### Added
1924
+ - Automatically publish to PyPI upon tagging [\#475](https://github.com/kivy/kivy-ios/issues/475) ([AndreMiras](https://github.com/AndreMiras))
1925
+ - Dedicated setup.py test workflow [\#474](https://github.com/kivy/kivy-ios/issues/474) ([AndreMiras](https://github.com/AndreMiras))
1926
+
1927
+ ### Fixed
1928
+ - Fixes a regression introduced during the linting [\#477](https://github.com/kivy/kivy-ios/issues/477) ([AndreMiras](https://github.com/AndreMiras))
1929
+ - More fixes to Numpy so that the binary is accepted by the App Store [\#473](https://github.com/kivy/kivy-ios/issues/473) ([lerela](https://github.com/lerela))
1930
+ - Do not build known broken recipes [\#471](https://github.com/kivy/kivy-ios/issues/471) ([AndreMiras](https://github.com/AndreMiras))
1931
+ - Fixes minor typos in the issue template [\#469](https://github.com/kivy/kivy-ios/issues/469) ([AndreMiras](https://github.com/AndreMiras))
1932
+ - Activates venv before venv build [\#464](https://github.com/kivy/kivy-ios/issues/464) ([AndreMiras](https://github.com/AndreMiras))
1933
+ - Fixes building in venv [\#462](https://github.com/kivy/kivy-ios/issues/462) ([AndreMiras](https://github.com/AndreMiras))
1934
+ - Cleanup - Removes vendored deps [\#454](https://github.com/kivy/kivy-ios/issues/454) ([misl6](https://github.com/misl6))
1935
+
1936
+ ### Changed
1937
+ - Updates README.md with install/usage from PyPI [\#476](https://github.com/kivy/kivy-ios/issues/476) ([AndreMiras](https://github.com/AndreMiras))
1938
+ - Moving to dedicated kivy\_ios/ package directory [\#472](https://github.com/kivy/kivy-ios/issues/472) ([AndreMiras](https://github.com/AndreMiras))
1939
+ - Bumps Cython version [\#470](https://github.com/kivy/kivy-ios/issues/470) ([misl6](https://github.com/misl6))
1940
+ - Uses new `cd` context manager more [\#465](https://github.com/kivy/kivy-ios/issues/465) ([AndreMiras](https://github.com/AndreMiras))
1941
+
1942
+
1943
+ ## [1.0.0] - 2020-05-02
1944
+ - Initial release