serious_python_darwin 4.4.2
serious_python_darwin: ^4.4.2 copied to clipboard
iOS and macOS implementations of the serious_python plugin
4.4.2 #
- iOS: framework bundle identifiers are now namespaced under the host app. Every Python C-extension ships as its own embedded framework, and each carried a fixed
org.python.<module>CFBundleIdentifier—org.python.ssl,org.python.hashlib, … — byte-identical in every app ever built with serious_python. SetSERIOUS_PYTHON_BUNDLE_IDto the app's bundle identifier and they becomecom.example.myapp.-sslinstead, matching what CPython's own iOS support does when it converts a.sointo a framework. This matters because a framework's bundle identifier also becomes its code signing identifier, which is the one field that survives thecodesign -fXcode applies at embed and again atexportArchive.Python.frameworkis covered too — it wasorg.python.pythonin every app; nothing resolves it by identifier (the string appears in no shipped binary and there are noCFBundleGetBundleWithIdentifierlookups), so the rename is inert at runtime.dart_bridge.frameworkis deliberately left atdev.flet.dartbridge, which is already a vendor-owned identifier rather than a shared placeholder. Unset, or set to something that isn't a valid bundle identifier, leaves the old defaults in place and prints a warning.flet buildsupplies it from your app's configured bundle id (flet-dev/flet#6731). - iOS: generated frameworks now carry Xcode's build-provenance keys in their
Info.plist. Every framework built from alib-dynload.so—_ssl,_hashlib, and the rest — previously shipped ten hand-written keys and not a singleDT*key, so to Apple's static analysis the bundle didn't look like anything Xcode had produced. They now carry the same key set Xcode stamps into a real framework (BuildMachineOSBuild,DTCompiler,DTPlatformBuild,DTPlatformName,DTPlatformVersion,DTSDKBuild,DTSDKName,DTXcode,DTXcodeBuild,UIDeviceFamily, andUIRequiredDeviceCapabilitieson the device slice), resolved from the SDK the release was built with. The simulator slice is also labelled correctly now — it previously claimedCFBundleSupportedPlatforms=iPhoneOS. See flet-dev/python-build#36. - Both changes above are hypotheses under test for the
ITMS-91065: Missing signatureApp Store rejection in flet-dev/flet#6724, neither is a confirmed fix. The shared bundle identifier is the stronger of the two: it accounts for every outcome we could find (BeeWare namespaces under the app and has no reports; a third-party OpenSSL xcframework with its own vendor identifier is reported to pass; ourorg.python.*and one other project's independent identifier both draw the rejection). Two further candidates were ruled out experimentally: a signature applied at the source can't matter (re-signing the wayexportArchivedoes destroys the certificate chain, team identifier and timestamp, leaving only the identifier string, which is derived fromCFBundleIdentifierfor an unsigned framework anyway), and the privacy manifest can't be the differentiator (a third-party OpenSSL xcframework the App Store accepts ships an empty stub, and our frameworks already carry a manifest — Apple emits noITMS-91061alongside the rejection). The check only fires for new apps, or updates that newly add a listed SDK, so existing published apps are unaffected either way. - Re-pins the bundled python-build snapshot to 20260727. No versions moved: Python (3.12.13 / 3.13.14 / 3.14.6), Pyodide, and
dart_bridge1.6.1 are unchanged from 20260726, and theInfo.plistchange above is the only functional difference on any platform.
4.4.1 #
- iOS:
_ssl.frameworkand_hashlib.frameworknow carry OpenSSL's official privacy manifest. Both extensions statically link OpenSSL, so Apple's App Store scan identifies them as containing BoringSSL / openssl_grpc — a listed third-party SDK that must declare a privacy manifest. The bundledPrivacyInfo.xcprivacywas a stub:NSPrivacyAccessedAPITypeswas an empty array, and it carried anNSPrivacyUsesNonStandardAPIskey that isn't part of Apple's schema. It is now byte-identical to the manifest OpenSSL publishes for its Apple builds, declaring the file-timestamp API access the library actually performs (NSPrivacyAccessedAPICategoryFileTimestamp, reasonC617.1). See flet-dev/python-build#35. - This does not resolve the
ITMS-91065: Missing signatureApp Store rejection reported in flet-dev/flet#6724, and shouldn't be read as a fix for it. That rejection cites the same two frameworks but arrives with no accompanyingITMS-91061, so Apple does find the manifest. Inspecting a built.ipaconfirms the frameworks reach Apple signed — valid Apple Distribution authority and team ID, with the manifest sealed into_CodeSignature/CodeResources— and that Xcode re-signs every embedded framework with the submitting team's identity at both the embed andexportArchivesteps, overwriting whatever signature the vendor applied. Root cause is still open; this change removes the one verifiable defect so it isn't a confound. - Re-pins the bundled python-build snapshot to 20260726. No versions moved: Python (3.12.13 / 3.13.14 / 3.14.6), Pyodide, and
dart_bridge1.6.1 are all unchanged from 20260725, and the privacy manifest above is the only functional difference on any platform.
4.4.0 #
- iOS/macOS:
dart_bridgenow ships as a dynamic framework, fixing built iOS apps crashing at startup withFailed to lookup symbol 'serious_python_run': dlsym(RTLD_DEFAULT, serious_python_run): symbol not found.dart_bridge's FFI entry points (serious_python_run,DartBridge_InitDartApiDL,DartBridge_EnqueueMessage,PyInit_dart_bridge) are resolved at runtime viadlsym— from Dart throughDynamicLibrary.process()and from Python throughimport dart_bridge. It previously shipped as a static archive linked into the host app executable, and an iOS executable exports nothing to the dynamic symbol table by default (the release build also strips local symbols), so those lookups failed. Only release/archive (device) builds were affected — debug/simulator builds don't dead-strip, so the failure did not reproduce there. Android was never affected: itsdart_bridgeis a dynamic.so, which exports its symbols.dart_bridge1.6.1 now buildsdart_bridge.xcframeworkas a dynamic framework (see flet-dev/dart-bridge#11 and #12), so it is embedded + signed into the app likePython.xcframeworkand its symbols stay exported. The SwiftPM-all_load/-force_loadretention, the CocoaPods-all_load, and the plugin's dead-strip keep-alive references are all removed — a loaded image needs none of them. - Re-pins the bundled python-build snapshot to 20260725 (
dart_bridge1.5.1 → 1.6.1). Python versions (3.12.13 / 3.13.14 / 3.14.6) are unchanged and the iOS/macOS CPython runtimes are byte-identical to 20260720.
4.3.6 #
- Re-pins the bundled python-build snapshot to 20260720 (
dart_bridge1.5.0 → 1.5.1). 1.5.1 is a Windows-only UTF-8 startup fix (seeserious_python_windows4.3.6); the iOS/macOS runtimes are functionally unchanged from 20260719.
4.3.4 #
- Re-pins the bundled python-build snapshot to 20260719 (previously 20260714). The snapshot un-prunes
_pyreplon Windows/Linux desktop (fixing a 3.14pydoc/pdbcrash — seeserious_python_windows/serious_python_linux4.3.4); iOS/macOS already shipped_pyrepl(un-pruned in 4.3.2), so these runtimes are byte-identical to 20260714. No iOS/macOS-affecting changes.
4.3.3 #
- Version bump aligning with the
serious_python_*4.3.3 release (a Windows build fix). No iOS/macOS-affecting changes.
4.3.2 #
- iOS: reconcile framework install-names for interdependent bundled dylibs (#223). Site-package
.so/.dylibs are wrapped into frameworks named by their dotted relative path (opt/lib/libarrow.dylib→opt.lib.libarrow.framework/opt.lib.libarrow), but the Mach-O install-id and every interdependent@rpathreference were left at their original bare name (@rpath/libarrow.dylib). Because each framework is aPackage.swiftbinaryTarget linked at launch, dyld could not resolve@rpath/libarrow.dylib(it looks forFrameworks/libarrow.dylib, which does not exist) and the app crashed before Python started — hitting any package that bundles a chain of interdependent libs (pyarrow'slibarrow/libarrow_compute/libarrow_python, llama-cpp-python'slibggml*/libllama). A new reconcile pass, run aftersync_site_packagesframeworks the libs, sets each framework's own install-id to@rpath/<fw>.framework/<fw>and rewrites every dependency pointing at a sibling's old id to that framework path, then re-signs. The Python/stdlib xcframeworks are left untouched. (This supersedes the 4.2.1 approach of preserving.dylibinstall-names, which only worked when every sibling happened to be loaded first.) - The reconcile pass fails the build — rather than silently swallowing — on a genuine
install_name_tool/codesignerror, notably insufficient Mach-O header space to grow a load command (which would otherwise leave a bare@rpathref and reproduce the launch crash), and records every framework slice's old install-id so a lib with divergent per-slice install names has all slices rewritten. - Bump the bundled python-build snapshot to
20260714(Python/dart_bridgeversions are unchanged), with two iOS fixes:_pyreplis no longer pruned from the bundled stdlib: Python 3.14'spdbimports_pyreplat module load, so anything importingpdb(e.g. pytest's debugging plugin) died withModuleNotFoundError: No module named '_pyrepl'on iOS (3.13'spdbdoesn't import it).- The
_posixshmemextension is now built into the iOS runtimes:multiprocessing.resource_tracker— imported transitively byimport multiprocessing(e.g. scikit-learn → joblib) — unconditionally imports it on posix, so with_multiprocessingenabled (since20260701) but_posixshmemmissing, anymultiprocessinguser died withModuleNotFoundError: No module named '_posixshmem'. Process spawning remains unsupported in the iOS sandbox — this only makes the shared-memory module importable.
4.3.1 #
- Version bump aligning with the
serious_python_*4.3.1 release.
4.3.0 #
- Bump
dart_bridgeto 1.5.0 (python-build snapshot20260708): multiprocessing child-interception exports (serious_python_is_mp_invocation/serious_python_main), kept alive against the host link's-dead_stripboth by__attribute__((used))in the archive and by keep-alive references inSeriousPythonPlugin.swift. See theserious_python4.3.0 notes. prepare_macos.sh/prepare_ios.sh: the extracteddart_bridge.xcframeworkindist_*is now keyed to the dart_bridge version (.dart_bridge_versionmarker) — previously a version bump kept staging the stale extraction from the earlier version.PYTHONINSPECT=1is no longer set by any platform implementation. It had no effect on the embedded interpreter, but it leaked into the process environment where any real interpreter child (e.g. a serviced multiprocessing worker) would inherit it and hang in interactive mode after its command completed.
4.2.1 #
- Framework-ize ctypes
.dylibshared libs (not just.soC-extensions) when syncing iOS site-packages, so.dylib-shipping packages (e.g.llama-cpp-python) load on the iOS simulator instead of failingdlopenwithincompatible platform (have 'iOS', need 'iOS-simulator'). Each.dylibbecomes a device+simulator xcframework +.fworkpointer, exactly like.so; unlike.so(whose id is rewritten to the framework path), the.dylibinstall-name is preserved so multi-lib packages resolve their sibling libs. The.sopath is unchanged. - Bump the bundled python-build snapshot to
20260701: the iOS runtime now builds the_multiprocessingextension (importable, not spawnable). Python/dart_bridgeversions are unchanged from20260630.
4.2.0 #
- Bump the bundled python-build snapshot to
20260630(dart_bridge1.4.1); aligns with theserious_python_*4.2.0 release.
4.1.1 #
- Version bump aligning with the
serious_python_*4.1.1 release.
4.1.0 #
- Version bump aligning with the
serious_python_*4.1.0 release.
4.0.0 #
- Swift Package Manager support (dual with CocoaPods). The plugin now builds under SPM as well as CocoaPods, so apps can use either integration (CocoaPods goes read-only in December 2026; Flutter ships SPM on by default since 3.44). A new
darwin/serious_python_darwin/Package.swiftbuilds the same Swift source as the podspec, withgetResourcePathresolvingBundle.moduleunder SPM (#if SWIFT_PACKAGE) and the frameworkpython.bundleunder CocoaPods.- SPM has no pod-install hook, so the staging the podspec
prepare_commanddoes runs on the host beforeflutter buildinstead:prepare_spm.shassembles the dist (prepare_<platform>.sh+sync_site_packages.sh) andstage_spm.shmaps it into the package layout —Python-{ios,macos}.xcframework+dart_bridge.xcframeworkas local-path binary targets, the iOS native C-extensions enumerated fromextra-xcframeworks/, andstdlib/site-packages/appas.copyresources. On iOS the extensions ship as embedded, signed frameworks (CPython's.fworkfinder resolves them); on macOS they load flat from the resource trees. - The manifest reads
SP_NATIVE_SET(a hash of the staged native set) so SwiftPM re-resolves when requirements / app / Python version change — SwiftPM caches its package graph on manifest text + environment, not on the staged dirs it enumerates. - The SPM path needs Flutter 3.44 / Dart 3.11; the plugin's minimum is unchanged because
Package.swiftis dormant on older Flutter (which uses the CocoaPods path).
- SPM has no pod-install hook, so the staging the podspec
prepareApp()returns the app dir from thepython.bundleresource (<resourcePath>/app); the app's Python sources ship unpacked as anappresource bundle next tostdlib+site-packages(no first-launch extraction).- Version bump aligning with the
serious_python_*4.0.0 release.
3.0.0 #
- In-process Python (dart_bridge FFI). The Python lifecycle is absorbed into
dart_bridge.xcframework(fromflet-dev/dart-bridge1.4.0) instead of a socket transport; the Swift plugin registers the dart_bridge inittab, the pod is declaredstatic_frameworkfor xcframework vendoring, and the embeddedPython.appis stripped fromPython.framework. - Breaking change: requires Flutter 3.44.2.
- The podspec resolves the Python version from the generated
python_versions.properties(a snapshot of python-build'smanifest.json) and passes the full version, build date anddart_bridgeversion toprepare_ios.sh/prepare_macos.sh(dart_bridge_versionis$4);SERIOUS_PYTHON_VERSIONis the knob, the per-field env vars are escape hatches. The prepare scripts re-extractdist_ios/dist_macoswhen the selected version changes (a version marker) so a clean build can't mix C-extension ABIs. - Remove the scaffold
getPlatformVersionmethod.
2.0.0 #
- Breaking change: default bundled Python version is now 3.14 (was 3.12). Apps built without an explicit
SERIOUS_PYTHON_VERSIONenv var pullpython-ios-dart-3.14.tar.gz/python-macos-dart-3.14.tar.gzfromflet-dev/python-build. SetSERIOUS_PYTHON_VERSION=3.12to preserve the previous default. - Multi-version Python support.
python_versioninserious_python_darwin.podspecreads fromSERIOUS_PYTHON_VERSION;prepare_ios.sh/prepare_macos.shalready took the version as$1and download the matching tarballs.
1.0.1 #
Improvements #
- Cache downloaded Python distribution tarballs (
python-android-dart-<py>-<abi>.tar.gz) across builds. ThedownloadDistArchive_*Gradle tasks now write to a persistent cache directory —$FLET_CACHE_DIR/python-build/v<python_version>/if the env var is set, otherwise~/.flet/cache/python-build/v<python_version>/— and useonlyIfModified true+useETag "all"so subsequent builds issue a conditional GET (If-None-Match/If-Modified-Since) againstobjects.githubusercontent.cominstead of re-downloading 30–100 MB per ABI per build. When the upstream release republishes a tarball at the same URL (e.g. a Python patch update under the existingv<py>release), the validators flip and the cache refreshes automatically; otherwise the build skips the download entirely.tempAndMove trueguards against partial downloads being kept in the cache (flet-dev/flet#6555, #208) by @FeodorFitsner.
Bug fixes #
1.0.0 #
- Breaking change:
--platformargument valuePyodidehas been renamed toEmscriptento match whatplatform.system()returns in the Pyodide runtime, so PEP 508 markers likeplatform_system != 'Emscripten'work consistently.
0.9.10 #
- Android: Add debug logs and deduplicate FFI imports.
- Android: Invalidate extracted assets when version keys change.
0.9.9 #
- Add zipDirectoryPosix to create POSIX-compliant app archives on Windows.
- Enforce C++20 standard for
serious_pythonplugin build. - Fix: Normalize
WINDIRpath for bundled DLLs in CMake. - Fix Logcat logging crash on some Android devices.
0.9.8 #
- Fix logging on Android.
0.9.7 #
- Fix app restart on Android 10.
- Redirect Python output to logcat.
0.9.6 #
- Make zipDirectory call asynchronous.
0.9.5 #
- Bump
archiveto^4.0.7. - Fixed iOS framework identifier generation.
0.9.3 #
- Fix: Hidden files in site-packages are skipped when building macOS app.
- Fix: Do not delete package metadata in
.dist-infodirectories (#164).
0.9.2 #
- Breaking change: multiple
--requirementsoptions ofpackagecommand must be passed as--requirements DEP_1 --requirements DEP_2 ...(or-r DEP_1 -r DEP_2 ...) instead of-r DEP_1,DEP_2,...to support dependency specifications with commas, e.g.pandas>=2.2,<3. - Fix site-packages packaging for Pyodide platform.
0.9.1 #
- Fix
serious_pythonto work on macOS 12 Monterey and built with Xcode 14.
0.9.0 #
- Set
MinimumOSVersionto13.0for generated Python frameworks. - iOS and macOS packaging: Python system libraries are put into
python.bundleto pass App Store verification. - On macOS, Windows, and Linux, application site packages are copied in an unpacked state to the application bundle to speed up the first launch.
- Pyodide 0.27.2
- Python 3.12.9
- Packaging
--cleanupoption replaced with two separate--cleanup-appand--cleanup-packagesoptions. - New packaging options
--cleanup-app-filesand--cleanup-package-filesto specify a list of globs to exclude files and directories from app and site packages. - New packaging
--skip-site-packagesoption to skip site packages installation for faster re-builds. - Packaging
--archoption accepts a list now.
0.8.7 #
- Fixed:
xcframeworksmigration script didn't work for sub-directories.
0.8.6 #
- Added
com.flet.serious_python_android.PythonActivityholder class withmActivityholding a reference to an app MainActivity. Needed forplyer. - Android plugin sets
MAIN_ACTIVITY_HOST_CLASS_NAMEenvironment variable with the name of activity holder class name (com.flet.serious_python_android.PythonActivity). - Android plugin sets
MAIN_ACTIVITY_CLASS_NAMEenvironment variable with a class name of an app MainActivity. - Android plugin sets
ANDROID_NATIVE_LIBRARY_DIRenvironment variable with the path to a directory containing app .so libraries. Needed for patchingctypes.find_library. - Changed behavior of
SERIOUS_PYTHON_ALLOW_SOURCE_DISTRIBUTIONSenvironment variable that should contain a comma-separated list of packages to allow installation from source distribution. - Fixed: iOS
site-packagestoxcframeworksmigration script supports bothlibrary.soandlibrary.{something}.so.
0.8.4 #
- Copy
site-packages/fluttercontents toSERIOUS_PYTHON_FLUTTER_PACKAGES. - Added
SERIOUS_PYTHON_ALLOW_SOURCE_DISTRIBUTIONSvariable to allow pip installing from source distributions.
0.8.3 #
- Remove
PYTHONOPTIMIZE=2to make CFFI work.
0.8.2 #
- Copy
.solibraries from{site-packages}/opttojniLibs.
0.8.1 #
0.8.0 #
- New packaging, not based on Kivy and with pre-built binary packages.
0.7.1 #
- Added
namespacedefinition to Android Gradle build. - Bump dependencies.
0.7.0 #
runPython()method to support running Python script.- Updated
flet_exampleto catch program output and errors,sys.exit()support. packagecommand to read dependencies frompyproject.toml.
0.6.1 #
--excludeoption forpackagecommand - to exclude directories and files from Python app package.- Re-create temp Python distributive directory on every run of
packagecommand.
0.6.0 #
--verboseflag - verbose output.--mobileflag - (removes.so) from app dest archive.--webflag for packaging for pyodide.--find-linksoption for installing pip dependencies from alternative sources (indexes).--dep-mappingsfor rewritingfletdependency to eitherflet-embedorflet-pyodide.--req-depsfor adding required dependencies likeflet-embedorflet-pyodide.--platformoption for use withsitecustomize.pyto tweak pip to pull platform-specific packages.- More structured regular output.
- Bump deps versions.
0.5.1 #
- Simplified Python initialization on Android.
0.5.0 #
- Python 3.11.6.
0.4.1 #
- Bumping version after fixing pubspec.yaml.
0.4.0 #
- macOS support.
0.3.0 #
Initial version.