Add a Swift package to your iOS app¶
You can add Swift Package Manager (SPM) dependencies to your iOS app under
[tool.kivy.ios.native.swift_packages]. kivyforge pins each remote package in
the lock and wires every package into the generated Xcode project; Xcode
resolves and builds them.
Before you begin¶
- Configure your iOS app.
- Decide whether you call the package from Python. Python reaches Swift code
through pyobjus, which sees only Objective-C-compatible APIs.
A pure-Swift API, such as one built on throwing functions, generics, or
subscripts, needs a small
@objcwrapper, called a shim.
Add a remote package¶
-
Declare the package by URL, version requirement, and the products to link:
[tool.kivy.ios.native.swift_packages] KeychainAccess = { url = "https://github.com/kishikawakatsumi/KeychainAccess", requirement = { from = "4.2.2" }, products = ["KeychainAccess"] }requirementtakes exactly one rule:exact,from,up_to_next_minor,range(a two-item list, lower bound inclusive and upper bound exclusive),branch, orrevision. -
Lock the project:
kivyforge lock -p ioskivyforge resolves the package with Xcode's Swift toolchain and pins the exact revision in
pylock.ios.toml.buildwrites that pin into the generated project'sPackage.resolved, so Xcode resolves the same revision.
Embedding a remote package
embed defaults to false for a remote package, because most remote
products resolve to static libraries, which have no framework to copy into
the app. If a remote package's product is a dynamic framework, set
embed = true explicitly. Setting embed = true on a static product fails
the Xcode build.
Add a local shim to call Swift from Python¶
To call a pure-Swift API from Python, write a local package that re-exports the
calls you need from an @objc class, and declare it with path. The
keychain-spm example uses this pattern:
[tool.kivy.ios.native.swift_packages]
KeychainAccess = { url = "https://github.com/kishikawakatsumi/KeychainAccess", requirement = { from = "4.2.2" }, products = ["KeychainAccess"], link = false, embed = false }
KeychainBridge = { path = "swift-shims", products = ["KeychainBridge"] }
KeychainBridgeis the shim in the project'sswift-shims/directory. ItsPackage.swiftdepends onKeychainAccessand declares a dynamic library product. A local package is linked and embedded by default.- Embedding the shim brings in its whole dynamic dependency closure, including
KeychainAccess. That is whyKeychainAccessis declaredlink = false, embed = false: the declaration still pins it in the lock without embedding it a second time.
A path must be relative to the project and must not point outside it.
Verify¶
Lock and build for the Simulator. The build fails if a package does not resolve:
kivyforge lock -p ios
kivyforge build -p ios --simulator
What's next¶
- Call iOS APIs with pyobjus to reach your shim's
@objcclass. - Open the iOS project in Xcode to inspect the resolved packages.
[tool.kivy.ios]reference.