Native modules¶
Cross-platform wrappers around device APIs that are not part of the
view tree: camera, GPS, file I/O, notifications, clipboard, share
sheet, deep links, permissions, connectivity, secure storage, battery,
haptics, biometrics, and the React Native core set of Keyboard,
Dimensions, PixelRatio, Device, Localization, and
AccessibilityInfo. Each module is a Swift and a Kotlin class
registered by name in the native runtime; the Python classes below are
facades that call them through
native_module,
with a Python implementation registered for the desktop and tests.
Return values are frozen dataclasses
(DeviceInfo, Locale,
KeyboardEvent, ...).
Readers of OS state are synchronous; anything that shows UI or waits on
the OS is a coroutine. Failures raise
NativeModuleError;
for example SecureStore.set_item and delete_item raise when the
native side reports a failed write or delete. For the call-site
patterns, the reactive hooks (use_app_state, use_net_info,
use_locales, use_screen_reader_enabled, use_reduce_motion), and
the runtime coroutines are scheduled on, see the
Native modules guide and the
Async + data guide.
Registry¶
Native module registry: name -> callable module, on device or off.
A native module is a named bag of methods implemented in Swift and
Kotlin (Camera, Storage, Haptics, ...). Python facades in
this package never touch platform APIs; they obtain a
NativeModule
through native_module
and call methods on it:
_clipboard = native_module("Clipboard")
_clipboard.call("set_string", text="hello")
text = _clipboard.call("get_string")
result = await _camera.call_async("take_photo")
On device the module is a
BridgeModule
that speaks the call(module, method, args_json) protocol described
in docs/concepts/bridge.md. Off device (tests, pn preview) the
same name resolves to a
PythonModule
wrapping a plain Python object with the same method names; the
built-in fallbacks live in pythonnative.native_modules.fallback and
third-party packages register theirs through the
pythonnative.modules entry point group or
register_python_module.
Modules can also push events (AppState changes, deep links,
battery updates). Facades subscribe with
NativeModule.add_listener;
native delivers through
dispatch_module_message
and Python implementations through
emit.
Classes:
| Name | Description |
|---|---|
NativeModuleError |
A native module method failed. |
NativeModule |
Common surface of bridge-backed and Python-backed modules. |
BridgeModule |
A module implemented natively; every call crosses the bridge once. |
PythonModule |
A module implemented by a plain Python object. |
Functions:
| Name | Description |
|---|---|
register_python_module |
Register |
unregister_python_module |
Remove a Python implementation registered for |
native_module |
Return the module registered under |
dispatch_module_message |
Route a native |
on_event |
Subscribe to |
emit |
Deliver |
Attributes:
| Name | Type | Description |
|---|---|---|
ENTRY_POINT_GROUP |
Entry-point group for Python (fallback / test) implementations of native modules. |
ENTRY_POINT_GROUP
module-attribute
¶
Entry-point group for Python (fallback / test) implementations of native modules.
NativeModuleError
¶
Bases: RuntimeError
A native module method failed.
Attributes:
| Name | Type | Description |
|---|---|---|
module |
Module name. |
|
method |
Method name. |
|
code |
Optional machine-readable code supplied by native. |
NativeModule
¶
NativeModule(name: str)
Common surface of bridge-backed and Python-backed modules.
Methods:
| Name | Description |
|---|---|
call |
Invoke |
call_async |
Invoke |
add_listener |
Subscribe to |
listener_count |
Number of listeners for |
call
¶
Invoke method synchronously and return its value.
Raises:
| Type | Description |
|---|---|
NativeModuleError
|
When the native side reports a failure. |
RuntimeError
|
When the method only completes asynchronously
(use |
add_listener
¶
Subscribe to event; returns an unsubscribe callable.
BridgeModule
¶
Bases: NativeModule
A module implemented natively; every call crosses the bridge once.
Methods:
| Name | Description |
|---|---|
call |
Call a native module method with a |
call_async |
Invoke |
Attributes:
| Name | Type | Description |
|---|---|---|
transport |
Any
|
The transport in use (resolved lazily on first access). |
call
¶
Call a native module method with a {"call_id", "args"} envelope.
PythonModule
¶
Bases: NativeModule
A module implemented by a plain Python object.
Methods are looked up by name on impl; keyword arguments are
forwarded. A method may be a coroutine function (or return an
awaitable), in which case call raises and call_async awaits
it. The implementation can push events with
emit.
Methods:
| Name | Description |
|---|---|
call |
Call a native module method with a |
call_async |
Invoke |
Attributes:
| Name | Type | Description |
|---|---|---|
impl |
Any
|
The implementation object, resolved on first use. |
impl
property
¶
impl: Any
The implementation object, resolved on first use.
Facades call native_module() at import time, so resolution is
deferred until the first method call; by then the package's
fallback implementation (or entry point) has had a chance to
register.
Raises:
| Type | Description |
|---|---|
KeyError
|
If no implementation is registered for the module. |
call
¶
Call a native module method with a {"call_id", "args"} envelope.
register_python_module
¶
Register impl as the off-device implementation of module name.
impl is an object (or a zero-arg factory returning one) whose
methods match the module's method names. Registering replaces any
earlier implementation and invalidates the cached module so the
next native_module
call picks it up.
unregister_python_module
¶
unregister_python_module(name: str) -> None
Remove a Python implementation registered for name (tests).
native_module
¶
native_module(name: str) -> NativeModule
Return the module registered under name for the current platform.
On iOS and Android this is always a
BridgeModule;
the native runtime decides whether the module exists when a method
is first called. Elsewhere it is the registered
PythonModule.
Off device the implementation is resolved lazily, on the first
method call, so facades can call this at import time; a missing
implementation surfaces then as KeyError.
dispatch_module_message
¶
Route a native callback("module", ...) payload.
{"call_id": n, "ok": ..., "value"|"error": ...} settles a
pending call_async; {"event": name, "payload": ...} fans
out to listeners.
on_event
¶
Subscribe to module/event without resolving the module.
Facades use this at import time to route native pushes (AppState
change, Linking url, ...) into their own listener lists.
Unlike NativeModule.add_listener
the subscription survives module re-creation and never touches the
platform. Returns an unsubscribe callable.
Desktop implementations¶
Pure-Python fallbacks for the built-in native modules.
On iOS and Android every module in this package is implemented in
Swift and Kotlin (PythonNativeKit and the pythonnative Gradle
module). Off device the same module names resolve to the plain Python
classes below, which keep the API usable without a device: in-memory
buffers, "unknown" states, and no-op feedback. Unit tests use them
directly; the browser preview implements a handful of modules in the
page (Alert, Clipboard, Device, ...) and routes the rest
here.
Each class has the same method names and argument shapes as its native
counterpart, so a facade in this package never branches on platform.
Apps and tests may swap any of these with
register_python_module.
Functions:
| Name | Description |
|---|---|
default_implementation |
Return the factory for the built-in Python fallback implementation of |
FallbackDevice
¶
Static device information for the host machine.
Returns the documented DeviceInfo keys plus app_dir and
cache_dir, which the native modules also return and
FileSystem reads.
FallbackAccessibilityInfo
¶
No screen reader, no reduce motion; announcements and focus are no-ops.
FallbackWebViews
¶
No page runs off device: eval_js answers the empty string.
FallbackKeyboard
¶
No keyboard off device: dismiss is a no-op and is_visible is False.
FallbackLocalization
¶
The host's LANG as the only locale and UTC as the time zone.
FallbackStorage
¶
Dict-backed AsyncStorage with optional JSON persistence.
Set PN_STORAGE_DIR to persist between runs (pn preview does
this); leave it unset in tests for a purely in-memory store.
FallbackAlert
¶
Records alerts and answers with scripted responses.
The log and response queue live on
Alert (Alert._test_log and
Alert.set_test_response) so tests have one place to look.
FallbackImages
¶
Header-only image measurement for PNG, JPEG, GIF, WebP, and BMP.
image_dimensions
¶
Return (width, height) in pixels from an image file header, or None.
Accessibility info¶
Screen-reader and reduce-motion state, announcements, and accessibility focus.
AccessibilityInfo mirrors React
Native's module of the same name over the native AccessibilityInfo
module (UIAccessibility on iOS, AccessibilityManager on Android).
The two readers answer from state the OS already holds, so they are
synchronous; announce and set_accessibility_focus hand a request
to the OS and return at once. Native pushes a change event with
{"screen_reader": bool, "reduce_motion": bool} whenever either
setting flips; off device, tests drive the same path through
dispatch_accessibility.
Prefer the use_screen_reader_enabled
and use_reduce_motion hooks inside
components; use the imperative API for non-UI code.
Example
Classes:
| Name | Description |
|---|---|
AccessibilityEvent |
Snapshot of the two accessibility settings PythonNative tracks. |
AccessibilityInfo |
Accessibility settings interface (synchronous readers + change listener). |
Functions:
| Name | Description |
|---|---|
dispatch_accessibility |
Record new settings and notify listeners (tests and native pushes). |
use_screen_reader_enabled |
Return whether a screen reader is running and re-render when that changes. |
use_reduce_motion |
Return whether Reduce Motion is on and re-render when that changes. |
AccessibilityEvent
dataclass
¶
AccessibilityInfo
¶
Accessibility settings interface (synchronous readers + change listener).
Raises:
| Type | Description |
|---|---|
NativeModuleError
|
If the native module fails. |
Methods:
| Name | Description |
|---|---|
is_screen_reader_enabled |
Return |
is_reduce_motion_enabled |
Return |
announce |
Ask the screen reader to speak |
set_accessibility_focus |
Move screen-reader focus to the element behind |
add_listener |
Subscribe to setting changes; returns an unsubscribe function. |
is_screen_reader_enabled
staticmethod
¶
is_screen_reader_enabled() -> bool
Return True while a screen reader (VoiceOver, TalkBack) is active.
is_reduce_motion_enabled
staticmethod
¶
is_reduce_motion_enabled() -> bool
Return True while the system Reduce Motion setting is on.
announce
staticmethod
¶
announce(message: str) -> None
Ask the screen reader to speak message (a no-op when none is running).
set_accessibility_focus
staticmethod
¶
set_accessibility_focus(ref: Any) -> None
Move screen-reader focus to the element behind ref.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
ref
|
Any
|
A |
required |
Raises:
| Type | Description |
|---|---|
ValueError
|
If |
add_listener
staticmethod
¶
add_listener(
callback: Callable[[AccessibilityEvent], None],
) -> Callable[[], None]
Subscribe to setting changes; returns an unsubscribe function.
Each callback receives an
AccessibilityEvent.
dispatch_accessibility
¶
Record new settings and notify listeners (tests and native pushes).
use_screen_reader_enabled
¶
use_screen_reader_enabled() -> bool
Return whether a screen reader is running and re-render when that changes.
Raises:
| Type | Description |
|---|---|
RuntimeError
|
If called outside a |
use_reduce_motion
¶
use_reduce_motion() -> bool
Return whether Reduce Motion is on and re-render when that changes.
Raises:
| Type | Description |
|---|---|
RuntimeError
|
If called outside a |
Keyboard¶
On-screen keyboard state and dismissal.
Keyboard mirrors React Native's Keyboard
over the native Keyboard module. is_visible reads state the OS
already holds and dismiss resigns the first responder, so both are
synchronous. Native pushes a change event with {"height",
"visible", "duration_ms"} on every show, hide, and resize (iOS
keyboardWillChangeFrame, Android WindowInsetsCompat.Type.ime());
the facade forwards the height to
platform_metrics so
use_keyboard_height and
KeyboardAvoidingView track it on
both platforms. Off device, tests drive the same path through
dispatch_keyboard.
Example
Classes:
| Name | Description |
|---|---|
KeyboardEvent |
One keyboard transition. |
Keyboard |
Keyboard interface (synchronous). |
Functions:
| Name | Description |
|---|---|
dispatch_keyboard |
Publish a keyboard transition to |
KeyboardEvent
dataclass
¶
One keyboard transition.
Attributes:
| Name | Type | Description |
|---|---|---|
height |
float
|
Keyboard height in layout units ( |
visible |
bool
|
Whether the keyboard is (or is about to be) on screen. |
duration_ms |
float
|
The platform's show/hide animation duration in
milliseconds ( |
Keyboard
¶
Keyboard interface (synchronous).
Raises:
| Type | Description |
|---|---|
NativeModuleError
|
If the native module fails. |
Methods:
| Name | Description |
|---|---|
dismiss |
Hide the keyboard by resigning the focused input (a no-op when none is focused). |
is_visible |
Return |
add_listener |
Subscribe to keyboard transitions; returns an unsubscribe function. |
dismiss
staticmethod
¶
Hide the keyboard by resigning the focused input (a no-op when none is focused).
add_listener
staticmethod
¶
add_listener(
callback: Callable[[KeyboardEvent], None],
) -> Callable[[], None]
Subscribe to keyboard transitions; returns an unsubscribe function.
Each callback receives a KeyboardEvent.
Dimensions and pixel ratio¶
Window and screen size, pixel density, and pixel rounding.
Dimensions and
PixelRatio mirror React Native's modules of
the same names. Neither talks to a native module: the screen host
publishes width, height, scale, font_scale,
screen_width, and screen_height into
platform_metrics on every layout
pass, and these classes read from there. That makes them usable
anywhere, including outside components; inside a component prefer
use_window_dimensions, which
re-renders on change.
Example
Classes:
| Name | Description |
|---|---|
DimensionsEvent |
Both sizes after a change, as React Native's |
Dimensions |
Window and screen size in layout units (pt on iOS, dp on Android). |
PixelRatio |
Convert between layout units and physical pixels. |
DimensionsEvent
dataclass
¶
DimensionsEvent(
window: WindowDimensions, screen: WindowDimensions
)
Both sizes after a change, as React Native's Dimensions listener receives them.
Attributes:
| Name | Type | Description |
|---|---|---|
window |
WindowDimensions
|
The area the app draws into. |
screen |
WindowDimensions
|
The whole display. |
Dimensions
¶
Window and screen size in layout units (pt on iOS, dp on Android).
Methods:
| Name | Description |
|---|---|
get |
Return the current window or screen size. |
add_listener |
Subscribe to size changes; returns an unsubscribe function. |
get
staticmethod
¶
get(which: DimensionsScope = 'window') -> WindowDimensions
Return the current window or screen size.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
which
|
DimensionsScope
|
|
'window'
|
Returns:
| Type | Description |
|---|---|
WindowDimensions
|
|
WindowDimensions
|
with |
WindowDimensions
|
and height are |
Raises:
| Type | Description |
|---|---|
ValueError
|
For a value other than |
add_listener
staticmethod
¶
add_listener(
callback: Callable[[DimensionsEvent], None],
) -> Callable[[], None]
Subscribe to size changes; returns an unsubscribe function.
The callback receives a
DimensionsEvent
only when the window or screen size (or density) actually changed,
not for keyboard or safe-area updates.
PixelRatio
¶
Convert between layout units and physical pixels.
Methods:
| Name | Description |
|---|---|
get |
Return physical pixels per layout unit ( |
get_font_scale |
Return the user's text-size multiplier ( |
get_pixel_size_for_layout_size |
Return the whole number of physical pixels |
round_to_nearest_pixel |
Round |
Device¶
Static device and application facts.
Device.info returns
one DeviceInfo record read from the native
Device module (UIDevice and the main bundle on iOS, Build and
PackageManager on Android, navigator in the browser preview).
Everything in it is already known to the OS, so the call is synchronous.
The native module returns the record's keys plus app_dir, the
writable data directory that
FileSystem resolves relative paths against.
DeviceInfo doesn't expose it; use FileSystem.app_dir().
Example
Classes:
| Name | Description |
|---|---|
DeviceInfo |
Facts about the device and the running application. |
Device |
Device information interface (synchronous). |
DeviceInfo
dataclass
¶
DeviceInfo(
platform: str,
os_version: str,
model: str,
manufacturer: str,
is_simulator: bool,
is_tablet: bool = False,
app_name: str = "",
app_version: str = "",
build_number: str = "",
bundle_id: str = "",
scale: float = 1.0,
font_scale: float = 1.0,
locale: str = "",
)
Facts about the device and the running application.
Attributes:
| Name | Type | Description |
|---|---|---|
platform |
str
|
|
os_version |
str
|
OS version string ( |
model |
str
|
Hardware model ( |
manufacturer |
str
|
Hardware vendor ( |
is_simulator |
bool
|
Running in the iOS Simulator or an Android emulator. |
is_tablet |
bool
|
The OS classifies the device as a tablet (iPad, or an Android device with a large smallest width). |
app_name |
str
|
The display name of the app. |
app_version |
str
|
The marketing version ( |
build_number |
str
|
The build identifier ( |
bundle_id |
str
|
Bundle identifier / application id. |
scale |
float
|
Physical pixels per layout unit. |
font_scale |
float
|
The user's text-size multiplier. |
locale |
str
|
The preferred locale as a BCP 47 language tag ( |
Device
¶
Device information interface (synchronous).
Raises:
| Type | Description |
|---|---|
NativeModuleError
|
If the native module fails. |
Methods:
| Name | Description |
|---|---|
info |
Return the device and app facts as a |
info
staticmethod
¶
info() -> DeviceInfo
Return the device and app facts as a DeviceInfo.
Keys the native module leaves out fall back to "", False,
or 1.0; keys it adds (app_dir) are ignored here.
Localization¶
User locales, layout direction, and time zone.
Localization reads the user's preferred
languages and time zone from the native Localization module
(Locale.preferredLanguages and TimeZone.current on iOS,
LocaleList.getDefault() and TimeZone.getDefault() on Android,
navigator.languages in the browser preview). Both readers answer
from state the OS already holds, so they are synchronous. Native pushes
a change event with {"locales": [...], "timezone": str} when the
user changes either setting; off device, tests drive the same path
through
dispatch_localization.
Prefer the use_locales hook inside
components; use the imperative API for non-UI code.
Example
Classes:
| Name | Description |
|---|---|
Locale |
One entry of the user's preferred-language list. |
Localization |
Locale and time-zone interface (synchronous). |
Functions:
| Name | Description |
|---|---|
dispatch_localization |
Record new locales (and optionally a time zone) and notify listeners. |
use_locales |
Return the preferred locales and re-render when the user changes them. |
Locale
dataclass
¶
One entry of the user's preferred-language list.
Attributes:
| Name | Type | Description |
|---|---|---|
language_tag |
str
|
BCP 47 tag ( |
language_code |
str
|
ISO 639 language ( |
region_code |
str
|
ISO 3166 region ( |
is_rtl |
bool
|
Whether the language is written right to left. |
Localization
¶
Locale and time-zone interface (synchronous).
Raises:
| Type | Description |
|---|---|
NativeModuleError
|
If the native module fails. |
Methods:
| Name | Description |
|---|---|
get_locales |
Return the user's preferred locales, most preferred first. |
get_timezone |
Return the device time zone as an IANA name ( |
is_rtl |
Return whether the preferred locale is written right to left. |
add_listener |
Subscribe to locale changes; returns an unsubscribe function. |
get_locales
staticmethod
¶
Return the user's preferred locales, most preferred first.
The list is empty only when the platform reports no locale at all.
get_timezone
staticmethod
¶
get_timezone() -> str
Return the device time zone as an IANA name ("America/New_York").
dispatch_localization
¶
Record new locales (and optionally a time zone) and notify listeners.
use_locales
¶
Return the preferred locales and re-render when the user changes them.
Raises:
| Type | Description |
|---|---|
RuntimeError
|
If called outside a |
Camera¶
Cross-platform camera and gallery access.
Both entry points are coroutines: await Camera.take_photo() returns
the saved image path (a str) or None if the user cancels. The
native Camera module presents UIImagePickerController (iOS) or
launches MediaStore.ACTION_IMAGE_CAPTURE / ACTION_PICK
(Android) and resolves the call when the picker finishes; Python only
awaits the promise. On both platforms the path points at the full-size
capture: Android hands the camera app a FileProvider URI as
EXTRA_OUTPUT rather than reading the thumbnail from the result.
Example
Classes:
| Name | Description |
|---|---|
Camera |
Camera and image-picker interface (static coroutines). |
Camera
¶
Camera and image-picker interface (static coroutines).
Methods:
| Name | Description |
|---|---|
take_photo |
Launch the device camera to capture a photo. |
pick_from_gallery |
Open the system gallery picker. |
take_photo
async
staticmethod
¶
Launch the device camera to capture a photo.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
quality
|
float
|
JPEG compression quality from 0 to 1 on iOS. Android's system capture application controls its output quality. |
0.9
|
allow_editing
|
bool
|
Present the iOS crop editor before saving. |
False
|
Returns:
| Type | Description |
|---|---|
Optional[str]
|
The saved full-size image path on iOS and Android alike, or |
Optional[str]
|
|
Optional[str]
|
present, as in the browser preview). |
Raises:
| Type | Description |
|---|---|
NativeModuleError
|
If the picker can't be presented, for example because another picker is already open. |
pick_from_gallery
async
staticmethod
¶
Open the system gallery picker.
Returns:
| Type | Description |
|---|---|
Optional[str]
|
The selected image path, or |
Raises:
| Type | Description |
|---|---|
NativeModuleError
|
If the picker can't be presented. |
Location¶
Cross-platform location / GPS access.
Location.get_current
is a coroutine that resolves to a (latitude, longitude) tuple, or
None if no fix is available (the user denied permission, location
services are off, or the request timed out).
The native Location module owns the CLLocationManager /
LocationManager session and resolves the call with
{"latitude", "longitude", "accuracy", "altitude", "timestamp"}.
The first call prompts for when-in-use permission on both platforms
(requestWhenInUseAuthorization on iOS, the
ACCESS_FINE_LOCATION runtime prompt on Android), so there is no
separate Permissions.request step unless you want to ask earlier.
Declare location_when_in_use in the [permissions] table of
pythonnative.toml so the manifest entry and Info.plist usage string
are generated.
Example
Classes:
| Name | Description |
|---|---|
Location |
GPS / location-services interface. |
Location
¶
GPS / location-services interface.
Methods:
| Name | Description |
|---|---|
get_current |
Request the device's current location. |
get_current_fix |
Like |
get_current
async
staticmethod
¶
get_current(
*,
accuracy: Literal["balanced", "high"] = "balanced",
timeout: float = 10.0
) -> Optional[Coords]
Request the device's current location.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
accuracy
|
Literal['balanced', 'high']
|
Balanced accuracy or the highest available accuracy. |
'balanced'
|
timeout
|
float
|
Maximum seconds to wait for a fix. |
10.0
|
Returns:
| Type | Description |
|---|---|
Optional[Coords]
|
|
Optional[Coords]
|
|
Optional[Coords]
|
request timed out). |
Raises:
| Type | Description |
|---|---|
NativeModuleError
|
If the native module fails. |
get_current_fix
async
staticmethod
¶
get_current_fix(
*,
accuracy: Literal["balanced", "high"] = "balanced",
timeout: float = 10.0
) -> Optional[Dict[str, float]]
Like get_current but returns the full fix dict.
Keys: latitude, longitude, and when the platform reports
them accuracy (meters), altitude (meters), speed
(m/s), heading (degrees), timestamp (Unix seconds).
File system¶
App-scoped file I/O.
FileSystem answers one question the
standard library can't, "where may this app write?", and then gets out
of the way: app_dir
comes from the native Device module, and
path turns
an app-relative name into a pathlib.Path you use like any other.
The read/write helpers are thin conveniences over that path; they
raise the same OSError subclasses open and os do
(FileNotFoundError, PermissionError, ...) rather than hiding
them behind None and False.
Relative paths are resolved against app_dir; absolute paths are used
as-is. Everything here is synchronous: it is local disk I/O on the
calling thread, exactly like the standard library.
Example
Classes:
| Name | Description |
|---|---|
FileSystem |
App-scoped file I/O. |
FileSystem
¶
App-scoped file I/O.
Every helper accepts an absolute path or a path relative to
app_dir,
and raises OSError (or a subclass) when the operation fails,
like the standard library it wraps.
Methods:
| Name | Description |
|---|---|
app_dir |
Return the app's writable data directory. |
path |
Resolve |
read_text |
Read a text file; raises |
write_text |
Write a text file, creating parent directories as needed. |
read_bytes |
Read a binary file. |
write_bytes |
Write a binary file, creating parent directories as needed. |
exists |
Return whether a file or directory exists. |
delete |
Delete a single file. |
list_dir |
Return the entry names in a directory ( |
get_size |
Return a file's size in bytes. |
ensure_dir |
Create a directory (and any missing parents) if needed; returns its |
join |
Join path components with the OS separator ( |
app_dir
staticmethod
¶
app_dir() -> str
Return the app's writable data directory.
On Android the result is Context.getFilesDir(). On iOS it is
the app's Documents directory. Off device, without
either runtime, a .pythonnative_data directory under the
user's home folder is used. The value comes from the native
Device module's info() and is cached after the first
call.
Returns:
| Type | Description |
|---|---|
str
|
Absolute path to the app's data directory. |
path
staticmethod
¶
path(path: PathLike = '') -> Path
Resolve path against app_dir and return it as a pathlib.Path.
Absolute paths are returned unchanged. With no argument, returns
app_dir itself.
read_text
staticmethod
¶
Read a text file; raises FileNotFoundError and friends like open does.
write_text
staticmethod
¶
Write a text file, creating parent directories as needed.
write_bytes
staticmethod
¶
write_bytes(path: PathLike, data: bytes) -> None
Write a binary file, creating parent directories as needed.
delete
staticmethod
¶
delete(path: PathLike, *, missing_ok: bool = False) -> None
Delete a single file.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
path
|
PathLike
|
Absolute or |
required |
missing_ok
|
bool
|
Ignore a missing file instead of raising
|
False
|
list_dir
staticmethod
¶
Return the entry names in a directory (app_dir by default), sorted.
Notifications¶
Local notifications and remote push registration.
Coroutines for requesting permission and scheduling / cancelling local
notifications, backed by the native Notifications module
(UNUserNotificationCenter on iOS, NotificationManager on
Android).
Call await Notifications.request_permission() before scheduling on either
platform. Android 13+ requests POST_NOTIFICATIONS; scheduling returns
False when notifications aren't enabled. Android delayed notifications use
OS-owned, inexact alarms and survive ordinary process death. Delivery may be
deferred by power management. Reboot, force-stop, and app removal clear alarms.
For remote (server-sent) pushes, enable the remote_notifications
capability in pythonnative.toml and call
Notifications.get_device_token() to register with APNs and receive
the device token your server needs. Android remote push requires
Firebase Cloud Messaging, which needs a per-app google-services.json
and is not wired up by the built-in module; get_device_token raises
NativeModuleError with code == "unsupported" there.
Example
Classes:
| Name | Description |
|---|---|
Notifications |
Local notification interface. |
Notifications
¶
Local notification interface.
Methods:
| Name | Description |
|---|---|
request_permission |
Request notification permission from the user. |
schedule |
Schedule a local notification. |
cancel |
Cancel a pending notification by its identifier (a no-op when none is pending). |
get_device_token |
Register for remote notifications and return the device token. |
request_permission
async
staticmethod
¶
request_permission() -> bool
Request notification permission from the user.
On Android 12 and below the manifest declaration is sufficient
and this returns True without prompting. On Android 13+
(API 33) the POST_NOTIFICATIONS runtime permission prompt
is shown if the user hasn't decided yet.
Returns:
| Type | Description |
|---|---|
bool
|
|
bool
|
the user declined (always |
Raises:
| Type | Description |
|---|---|
NativeModuleError
|
If the native module fails. |
schedule
async
staticmethod
¶
schedule(
title: str,
body: str = "",
*,
delay_seconds: float = 0,
identifier: str = "default"
) -> bool
Schedule a local notification.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
title
|
str
|
Notification title. |
required |
body
|
str
|
Notification body text. |
''
|
delay_seconds
|
float
|
Seconds from now until delivery. Use |
0
|
identifier
|
str
|
Stable ID used by
|
'default'
|
Returns:
| Type | Description |
|---|---|
bool
|
|
bool
|
notification permission (so nothing was scheduled). |
Raises:
| Type | Description |
|---|---|
NativeModuleError
|
If the native module fails. |
cancel
async
staticmethod
¶
cancel(identifier: str = 'default') -> None
Cancel a pending notification by its identifier (a no-op when none is pending).
get_device_token
async
staticmethod
¶
Register for remote notifications and return the device token.
On iOS this calls registerForRemoteNotifications and waits
for the APNs callback; the token is a lowercase hex string your
server passes to APNs. Requires the remote_notifications
capability (which adds the aps-environment entitlement) and
a real device (the simulator has no APNs connection).
Returns:
| Type | Description |
|---|---|
Optional[str]
|
The APNs token, or |
Optional[str]
|
push service to register with). |
Raises:
| Type | Description |
|---|---|
NativeModuleError
|
On Android, where the built-in module
has no push registration; |
Clipboard¶
Cross-platform clipboard access.
Clipboard reads and writes the system
pasteboard through the native Clipboard module (UIPasteboard
on iOS, ClipboardManager on Android). The pasteboard lives in
process memory on both platforms, so every method is synchronous.
Off device the module is a process-local string buffer, which keeps it
usable in pn preview and unit tests.
Example
Classes:
| Name | Description |
|---|---|
Clipboard |
System clipboard interface (synchronous). |
Clipboard
¶
System clipboard interface (synchronous).
Raises:
| Type | Description |
|---|---|
NativeModuleError
|
If the native module reports a failure. |
Methods:
| Name | Description |
|---|---|
set_string |
Copy |
get_string |
Return the current clipboard string ( |
has_string |
Return |
Share¶
Present the system share sheet.
Share.share is a coroutine that opens
UIActivityViewController (iOS) or an ACTION_SEND chooser
(Android) through the native Share module and resolves to True
once the user completes a share or False if they dismiss it.
Example
Classes:
| Name | Description |
|---|---|
Share |
System share-sheet interface. |
Share
¶
System share-sheet interface.
Methods:
| Name | Description |
|---|---|
share |
Open the share sheet with |
share
async
staticmethod
¶
share(
*,
message: Optional[str] = None,
url: Optional[str] = None,
title: Optional[str] = None
) -> bool
Open the share sheet with message / url.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
message
|
Optional[str]
|
Text body to share. |
None
|
url
|
Optional[str]
|
A URL to share (combined with |
None
|
title
|
Optional[str]
|
Chooser title (Android) / subject (iOS mail). |
None
|
Returns:
| Type | Description |
|---|---|
bool
|
|
bool
|
dismissed the sheet or the platform has no share UI (tests). |
Raises:
| Type | Description |
|---|---|
NativeModuleError
|
If the sheet could not be presented. |
Linking¶
Open URLs, deep links, and the system settings page.
Linking wraps UIApplication.openURL /
Intent(ACTION_VIEW) (in the native Linking module) so a Python
app can hand a URL (https:, mailto:, tel:, a custom
scheme, ...) to the OS.
Outbound methods hand the URL to the OS and return at once, so they
are synchronous; the bool says whether the platform accepted the
request. Off device they return False.
Inbound deep links flow the other way: declare your schemes in
pythonnative.toml (app.url_schemes) and the native module
pushes a url event for every URL that opens the app, which lands in
dispatch_url. The
URL that cold-started the app is kept and returned by
get_initial_url; later URLs reach subscribers added with
add_listener.
Example
Classes:
| Name | Description |
|---|---|
Linking |
System URL / deep-link interface (synchronous). |
Functions:
| Name | Description |
|---|---|
set_interceptor |
Install a hook that sees each deep link first and may consume it. |
set_initial_url |
Record the launch URL (or clear it with |
dispatch_url |
Deliver an inbound deep link. |
Linking
¶
System URL / deep-link interface (synchronous).
Raises:
| Type | Description |
|---|---|
NativeModuleError
|
If the native module fails. |
Methods:
| Name | Description |
|---|---|
open_url |
Hand |
can_open_url |
Return |
open_settings |
Open this app's entry in the system Settings app. |
get_initial_url |
Return the URL that launched the app, if any. |
add_listener |
Subscribe to deep links that arrive while the app is running. |
open_url
staticmethod
¶
Hand url to the OS. Returns True if it was accepted.
can_open_url
staticmethod
¶
Return True when some installed app can handle url.
open_settings
staticmethod
¶
open_settings() -> bool
Open this app's entry in the system Settings app.
get_initial_url
staticmethod
¶
Return the URL that launched the app, if any.
add_listener
staticmethod
¶
Subscribe to deep links that arrive while the app is running.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
callback
|
Callable[[str], None]
|
Called with the full URL string for every inbound deep link (including the initial one, which is dispatched right after startup). |
required |
Returns:
| Type | Description |
|---|---|
Callable[[], None]
|
A zero-arg function that unsubscribes when called. |
set_interceptor
¶
Install a hook that sees each deep link first and may consume it.
Debug builds install the dev client's connect-link handler here, so
pn-<app id>://connect links pair the app with pn start
without becoming the app's initial URL. interceptor(url) returns
True to consume the link.
set_initial_url
¶
Record the launch URL (or clear it with None).
dispatch_url
¶
dispatch_url(url: str) -> None
Deliver an inbound deep link.
The first URL ever dispatched is also recorded as the initial URL (a cold start from a deep link reaches Python only after the interpreter boots, so native can't report it earlier than this).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
url
|
str
|
The full URL string that opened the app. |
required |
Permissions¶
Runtime permission checks and requests.
Permissions normalizes the very different
iOS and Android permission models behind two calls, both served by the
native Permissions module:
await check(permission): returns a status without prompting. It isasyncbecause some platform settings APIs (notification settings on iOS, for one) answer asynchronously.await request(permission): shows the system prompt (if needed) and resolves to the resulting status.
Statuses are "granted", "denied", "blocked" (denied with
"don't ask again" / Settings required), or "undetermined".
Permission names are the same words you declare in the
[permissions] table of pythonnative.toml, so the string that
puts NSCameraUsageDescription in your Info.plist is the string you
pass here: "camera", "microphone", "photo_library",
"location_when_in_use", "contacts", "notifications". The
full list is RUNTIME_PERMISSIONS;
capabilities that have no runtime prompt (vibration,
background_fetch, ...) are declared in the config only. A name
outside the list raises ValueError before anything reaches native.
Example
Classes:
| Name | Description |
|---|---|
Permissions |
Runtime permission interface. |
Attributes:
| Name | Type | Description |
|---|---|---|
PermissionStatus |
Outcome of a check or request. |
|
PermissionName |
A capability that has a runtime prompt; the same names as |
|
RUNTIME_PERMISSIONS |
Every permission name |
PermissionStatus
module-attribute
¶
PermissionStatus = Literal[
"granted", "denied", "blocked", "undetermined"
]
Outcome of a check or request.
PermissionName
module-attribute
¶
PermissionName = Literal[
"camera",
"microphone",
"photo_library",
"location_when_in_use",
"contacts",
"notifications",
]
A capability that has a runtime prompt; the same names as [permissions] in pythonnative.toml.
RUNTIME_PERMISSIONS
module-attribute
¶
RUNTIME_PERMISSIONS = (
"camera",
"microphone",
"photo_library",
"location_when_in_use",
"contacts",
"notifications",
)
Every permission name check / request accept, in the [permissions] vocabulary.
Permissions
¶
Runtime permission interface.
Raises:
| Type | Description |
|---|---|
ValueError
|
For a permission name outside
|
NativeModuleError
|
If the native module fails. |
Methods:
| Name | Description |
|---|---|
check |
Return the current status of |
request |
Prompt for |
check
async
staticmethod
¶
check(permission: PermissionName) -> PermissionStatus
Return the current status of permission without prompting.
A coroutine, like request: await pn.Permissions.check("camera").
request
async
staticmethod
¶
request(permission: PermissionName) -> PermissionStatus
Prompt for permission (if needed) and return the result.
Off device (pn preview, tests) the answer is always
"undetermined": there is no prompt to show.
App state¶
Foreground / background app lifecycle state.
AppState exposes the current lifecycle phase
("active", "inactive", or "background") and lets you
subscribe to transitions. The native AppState module pushes a
change event on every transition; off device, tests drive the same
path through
dispatch_app_state.
Prefer the use_app_state hook inside
components; use the imperative API for non-UI code.
Example
Classes:
| Name | Description |
|---|---|
AppState |
App lifecycle state interface. |
Functions:
| Name | Description |
|---|---|
dispatch_app_state |
Update the current state and notify every listener. |
use_app_state |
Subscribe a component to |
AppState
¶
App lifecycle state interface.
Methods:
| Name | Description |
|---|---|
current_state |
Return the current lifecycle phase. |
add_listener |
Subscribe to lifecycle changes. |
dispatch_app_state
¶
Update the current state and notify every listener.
Unknown values are ignored so a misbehaving host can't push garbage into the tree.
Network connectivity¶
Network connectivity state.
NetInfo reports whether the device is online
and over what kind of connection. fetch returns a snapshot dict;
add_listener (and the use_net_info
hook) deliver live updates pushed by the native NetInfo module
(NWPathMonitor on iOS, ConnectivityManager.NetworkCallback on
Android) as change events. Off device, tests push snapshots through
dispatch_net_info.
A snapshot looks like::
{"is_connected": True, "type": "wifi", "is_internet_reachable": True}
type is one of "wifi", "cellular", "ethernet",
"none", or "unknown".
Classes:
| Name | Description |
|---|---|
NetInfo |
Network connectivity interface. |
Functions:
| Name | Description |
|---|---|
dispatch_net_info |
Push a new connectivity snapshot and notify listeners. |
use_net_info |
Subscribe a component to |
NetInfo
¶
Network connectivity interface.
Methods:
| Name | Description |
|---|---|
fetch |
Return a fresh snapshot of connectivity state. |
add_listener |
Subscribe to connectivity changes; returns an unsubscribe fn. |
dispatch_net_info
¶
Push a new connectivity snapshot and notify listeners.
Secure storage¶
Encrypted key/value storage for secrets (tokens, credentials).
SecureStore persists small string values
in the iOS Keychain and Android EncryptedSharedPreferences (the
native SecureStore module), the right place for auth tokens and
other secrets that AsyncStorage (plain,
unencrypted) should never hold.
Both backing stores complete on the calling thread, so every method is
synchronous. Reads return Optional[str]; writes and deletes return
nothing and raise
NativeModuleError
when the native store reports failure. Off device the module falls back to an in-process dict
so code paths stay exercisable without a device Keychain.
Example
Classes:
| Name | Description |
|---|---|
SecureStore |
Encrypted secret storage (synchronous). |
SecureStore
¶
Encrypted secret storage (synchronous).
Raises:
| Type | Description |
|---|---|
NativeModuleError
|
If the Keychain / EncryptedSharedPreferences
operation fails (for example a Keychain entitlement problem),
including when the native side reports |
Methods:
| Name | Description |
|---|---|
set_item |
Store |
get_item |
Return the value for |
delete_item |
Delete |
set_item
staticmethod
¶
Store value under key, replacing any previous value.
Raises:
| Type | Description |
|---|---|
NativeModuleError
|
If the store refused the write (the native
module returned |
get_item
staticmethod
¶
Return the value for key, or None if absent.
delete_item
staticmethod
¶
delete_item(key: str) -> None
Delete key; deleting a key that isn't stored is not an error.
Raises:
| Type | Description |
|---|---|
NativeModuleError
|
If the store refused the delete (the native
module returned |
Battery¶
Battery level and charging state.
Battery reports the current charge fraction
(0.0 to 1.0, or -1.0 when the platform doesn't know) and
charging state, and lets you subscribe to changes. Both getters read a
value the OS already holds, so they are synchronous. The native
Battery module pushes a change event with {"level", "state"};
off device, tests drive the same path through
dispatch_battery.
Classes:
| Name | Description |
|---|---|
Battery |
Battery interface (synchronous getters + change listener). |
Functions:
| Name | Description |
|---|---|
dispatch_battery |
Notify listeners of a battery change. |
Battery
¶
Battery interface (synchronous getters + change listener).
Raises:
| Type | Description |
|---|---|
NativeModuleError
|
If the native module fails. |
Methods:
| Name | Description |
|---|---|
get_level |
Return the charge fraction in |
get_state |
Return |
add_listener |
Subscribe to battery changes; returns an unsubscribe fn. |
Haptics & vibration¶
Haptic feedback and raw vibration.
Two interfaces live here, both backed by the native Haptics module:
Haptics: semantic, iOS-style feedback (impact / notification / selection) backed byUIFeedbackGeneratoron iOS andVibrationEffectpatterns on Android.Vibration: a blunt "buzz for N milliseconds" interface for cases where you want an explicit duration.
Every method is synchronous (the OS queues the effect and returns). Missing hardware is not an error: on a device without a Taptic Engine or vibrator, and off device the native module simply does nothing.
Classes:
| Name | Description |
|---|---|
Haptics |
Semantic haptic feedback (synchronous). |
Vibration |
Raw vibration control (synchronous). |
Haptics
¶
Semantic haptic feedback (synchronous).
Raises:
| Type | Description |
|---|---|
NativeModuleError
|
If the native module fails. |
Methods:
| Name | Description |
|---|---|
impact |
Play a physical "impact" tap of the given |
notification |
Play a success / warning / error notification pattern. |
selection |
Play the light "selection changed" tick. |
Vibration
¶
Raw vibration control (synchronous).
Raises:
| Type | Description |
|---|---|
NativeModuleError
|
If the native module fails. |
Methods:
| Name | Description |
|---|---|
vibrate |
Vibrate for |
cancel |
Cancel an in-progress vibration (Android only). |
Biometrics¶
Biometric authentication (Face ID / Touch ID / fingerprint).
Biometrics gates an action behind the
device's biometric hardware via LAContext (iOS) and
BiometricPrompt (Android), both implemented in the native
Biometrics module.
is_available is synchronous (a capability lookup); authenticate
is a coroutine that presents the system prompt and resolves to True
on success or False when the user fails or cancels the prompt.
Example
Classes:
| Name | Description |
|---|---|
Biometrics |
Biometric authentication interface. |
Biometrics
¶
Biometric authentication interface.
Raises:
| Type | Description |
|---|---|
NativeModuleError
|
If the native module fails. |
Methods:
| Name | Description |
|---|---|
is_available |
Return |
authenticate |
Present the biometric prompt; resolve |
Next steps¶
- See guidance and permission setup in Native modules guide.
- Accessibility settings and hooks: Platform & Accessibility.
- Write your own: Native modules guide.