FAQ¶
Conceptual questions about PythonNative. For specific error messages and their fixes, see Troubleshooting.
Why "PythonNative" and not, say, Toga or Kivy?¶
PythonNative renders real native widgets through Swift and Kotlin
component managers. A pn.Text becomes a UILabel /
TextView; a pn.Button becomes a UIButton / Button.
Platform controls provide native behavior. Applications still need appropriate
accessibility labels, roles, and testing on each deployment target.
The component model is React-style (functions plus hooks plus a reconciler) so you get a familiar declarative API on top of those native widgets. Python runs on its own application thread and commits through a versioned bridge to a shared C++ renderer core, which validates and lays out each commit before the platform's UI thread mounts it.
Can I write Android-only or iOS-only code?¶
Yes. Two patterns:
-
Branch on
IS_ANDROID/IS_IOS/IS_WEBfor small differences inside a shared component:from pythonnative.utils import IS_ANDROID, IS_IOS, IS_WEB if IS_ANDROID: ... elif IS_IOS: ... elif IS_WEB: ...pn previewandpn startsetPN_PLATFORM=web, soIS_WEBisTruein the browser preview; see the Browser preview guide. For a declarative alternative, usePlatform.selectwith the"web"key. -
Per-platform native modules for larger pieces (a custom widget, a device API). Implement once per platform behind a single Python facade. See Native modules guide.
How do I add a new widget?¶
Declare a frozen Props dataclass, call
define_component(name, props)
to get a typed element factory, generate the native contract, and
implement a Swift PNComponentManager and a Kotlin ComponentManager
under the same name. Headless tests and the browser preview need no
extra Python code. Step-by-step instructions live in
Custom native components.
Does PythonNative work on the desktop or the web?¶
For previewing, yes. pn preview renders your app in a browser tab
inside a phone frame, with Fast Refresh on every save. It's the fastest
inner loop: see your real UI and iterate in seconds without booting a
simulator or deploying to a device. The page runs the same renderer core as
the mobile apps, compiled to WebAssembly, and shares Python components,
hooks, reconciliation, and logical navigation with them; it implements
widgets in the DOM. See the
Browser preview guide.
The browser preview is a development tool, not a production target:
platform chrome and fonts are approximated, most device APIs are
simulated, and there's no web or desktop packaging. Ship to devices
with pn run android / pn run ios and pn build.
The core (components, hooks, reconciler) is also platform-agnostic and runs headless with a fake backend; that's how the unit-test suite works.
How do I package and distribute my app?¶
pn run android and pn run ios produce installable artifacts in
build/:
- Android:
build/android/android_template/app/build/outputs/apk/. - iOS:
build/ios/ios_template/build/Build/Products/Debug-iphonesimulator/ios_template.app.
For release distribution, treat the staged template directory as a normal Android Studio / Xcode project (sign, archive, upload via Play Console / App Store Connect).
Can I use any Python package?¶
Most of them. List packages in [requirements].packages in
pythonnative.toml and the pn CLI resolves them for the phone,
not for your laptop, then bundles them into the app:
- Pure-Python packages (requests, httpx, pydantic-core-free libraries, and so on) work everywhere.
- Binary wheels work when the package publishes wheels for the
target: iOS wheels (PEP 730,
ios_13_0_arm64_iphoneosand the Simulator tags) from the BeeWare index, and Android wheels from the Chaquopy index. numpy, Pillow, cryptography, cffi, lxml, and pandas all resolve out of the box today. - No wheel for the target is a build-time error, reported by
pn depswith the package name and the target that failed, never a silent import error on the device.
Run pn deps to see how every requirement resolves for each iOS and
Android target before you build. The
PyPI packages guide covers the details
and the live compatibility matrix.
Don't put pythonnative itself in [requirements].packages; the CLI
bundles the installed copy directly.
Where do flex, padding, and position: "absolute" actually run?¶
In the renderer core, a C++ library with Yoga built in that every target
links: the iOS and Android apps, the browser preview (as WebAssembly), and
the pythonnative._core extension headless tests use. Python sends styles
in each commit; the core lays out off the UI thread, asks the platform to
measure text and controls, and returns changed frames to Python. The
layout rules are shared, but platform fonts and controls can have
different intrinsic sizes. See Layout engine.
How is state shared across screens?¶
Every screen is part of one component tree, so the usual tools work across screens:
- A
pn.Storefor app-wide, long-lived state. Define it at module level, change it with plain functions that callstore.update(...), and read it withuse_store. A selector (pn.use_store(store, lambda s: s.unread)) re-renders a component only when the value it reads changes. It fills the role of Zustand or Redux in a React Native app. use_context/Context.Providerfor tree-scoped values (the current user, a repository object). Place the provider above theNavigationContainerso every screen can read it.- Screen params for the data a screen needs to show: pass an id as a
parameter (
nav.push(ItemScreen(id=42))) and look the record up in the screen.
See Managing state for when to use each, and for persisting state across launches.
How do I navigate between screens?¶
Define your screens as components, list them in a module-level
StackNavigator,
TabNavigator, or
DrawerNavigator, and render it with
NavigationContainer. From a
screen, call use_navigation and pass
the destination as a call to its component:
nav.push(ItemScreen(id=42)). The screen's parameters are its route
params, so the type checker verifies them. See the
Navigation guide.
Why hooks instead of class components?¶
Hooks are smaller (no inheritance), composable (a custom hook is just a Python function that calls other hooks), and produce simpler diffs. The React community's experience over the last few years made the choice straightforward.
Why function components and not just plain functions?¶
The @pn.component decorator establishes a hook context for the
function call. Without it, hooks have no slot to attach state to and
will raise. The decorator also gives the reconciler a stable
identity for the function so it can keep state across re-renders.
How do I do animations?¶
Two strategies, depending on the cadence:
- State-driven (e.g., a fade triggered by a button press): keep
the value in
use_stateand let the reconciler push updates. Fine up to a few updates per second. - Frame-driven (e.g., a spring animation): bind an
AnimatedValueinto anAnimated.Viewstyle and drive it withAnimated.springorAnimated.timing. Native animation graphs update supported bindings without running Python on every frame. See the Animations guide for examples and fallback cases.
Is there async/await support?¶
Yes, and it's the core of the framework. PythonNative runs a single
standard asyncio loop on a dedicated application thread. Native UI threads
own widgets, scrolling, and animation frames. Components themselves can be async def (pair
them with Suspense for loading states),
use_effect accepts coroutine callbacks and cancels them on unmount,
use_resource fetches during render, and
native modules like Camera and Location are awaitable. From a
synchronous event handler, kick off work with
pn.run_async. See the
Async + data guide.
How is this different from Toga, BeeWare, Kivy, Briefcase?¶
| Tool | Model | Widgets |
|---|---|---|
| PythonNative | Declarative components plus reconciler | Real native (UILabel, TextView) via Swift / Kotlin component managers |
| Toga | Imperative widgets | Real native via per-platform backend |
| Kivy | Imperative widgets | Custom OpenGL renderer |
| Briefcase | Packaging only (no widgets) | n/a |
PythonNative also has a built-in pn CLI for the
build / install / hot-reload loop, so the equivalent of "Briefcase"
is included.
Where do I file bugs and feature requests?¶
GitHub issues. Smaller fixes and docs improvements are welcome as pull requests without a prior issue. See Contributing.
Next steps¶
- Walk through your first app: Getting started.
- Read the runtime model: Mental model.
- Browse the API: Package overview.