Skip to content

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, and biometrics. Each module is implemented twice (once per platform) and dispatches at runtime based on the IS_ANDROID and IS_IOS flags from pythonnative.utils, with a safe desktop fallback.

Both synchronous and coroutine APIs exist (chosen to match the platform call). For the call-site patterns, the reactive use_app_state / use_net_info hooks, and the runtime coroutines are scheduled on, see the Native modules guide and the Async + data guide.

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. Internally each call instantiates a fresh native delegate / activity request and bridges its completion onto the PythonNative asyncio runtime, so callers don't have to know whether the picker is backed by UIImagePickerController (iOS) or Intent(MediaStore.ACTION_IMAGE_CAPTURE) (Android).

Example
import pythonnative as pn

async def add_photo():
    path = await pn.Camera.take_photo()
    if path is None:
        return  # user cancelled
    await save_to_album(path)

Classes:

Name Description
Camera

Camera and image-picker interface.

Functions:

Name Description
deliver_android_activity_result

Forward an Activity result to the registered camera coroutine.

Camera

Camera and image-picker interface.

All methods are static coroutines. They dispatch to the iOS or Android implementation at call time based on the runtime platform.

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

take_photo(**options: Any) -> Optional[str]

Launch the device camera to capture a photo.

Parameters:

Name Type Description Default
**options Any

Reserved for platform-specific tuning. Currently unused; future kwargs (e.g., quality, flash_mode) will land here.

{}

Returns:

Type Description
Optional[str]

The saved image path, or None if the user cancelled or

Optional[str]

no camera is available.

pick_from_gallery(**options: Any) -> Optional[str]

Open the system gallery picker.

Parameters:

Name Type Description Default
**options Any

Reserved for platform-specific tuning.

{}

Returns:

Type Description
Optional[str]

The selected image path, or None if the user cancelled.

deliver_android_activity_result

deliver_android_activity_result(request_code: int, result_code: int, data: Any) -> bool

Forward an Activity result to the registered camera coroutine.

The host Activity should call this from onActivityResult so the pending take_photo / pick_from_gallery awaitable receives a path. Returns True if a Python callback was invoked (so the host can short-circuit further handlers).

Location

Cross-platform location / GPS access.

Location.get_current is a coroutine that resolves to a (latitude, longitude) tuple, or None if no recent fix is available or the user denies permission.

Permission prompts are triggered the first time a location-using API is called; ensure the appropriate manifest entries (android.permission.ACCESS_FINE_LOCATION) and Info.plist keys (NSLocationWhenInUseUsageDescription) are present.

Example
import pythonnative as pn

async def show_position():
    coords = await pn.Location.get_current()
    if coords is None:
        return
    lat, lon = coords
    print(f"You are at {lat:.5f}, {lon:.5f}")

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 async staticmethod

get_current(**options: Any) -> Optional[Coords]

Request the device's current location.

Parameters:

Name Type Description Default
**options Any

Reserved for platform-specific tuning (e.g., accuracy, timeout).

{}

Returns:

Type Description
Optional[Coords]

(latitude, longitude) if a fix was obtained, otherwise

Optional[Coords]

None.

File system

Cross-platform app-scoped file I/O.

Provides static helpers for reading, writing, and deleting files in the app's sandboxed storage area. Relative paths are resolved against FileSystem.app_dir; absolute paths are used as-is.

Example
from pythonnative import FileSystem

FileSystem.write_text("notes/today.txt", "Hello, file system!")
print(FileSystem.read_text("notes/today.txt"))

Classes:

Name Description
FileSystem

App-scoped file I/O.

FileSystem

App-scoped file I/O.

Every instance method operates on either an absolute path or a path relative to app_dir. Errors are swallowed and reported as falsy return values (None for readers, False for writers) so callers can treat the API as best-effort.

Methods:

Name Description
app_dir

Return the app's writable data directory.

read_text

Read a text file.

write_text

Write a text file, creating parent directories as needed.

exists

Return whether a file or directory exists.

delete

Delete a single file.

list_dir

List the entries in a directory.

read_bytes

Read a binary file.

write_bytes

Write a binary file, creating parent directories as needed.

get_size

Return file size in bytes.

ensure_dir

Create a directory (and any missing parents) idempotently.

join

Join path components using 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 user's Documents directory. On a desktop machine without either runtime, a .pythonnative_data directory is created under the user's home folder.

Returns:

Type Description
str

Absolute path to the app's data directory.

read_text staticmethod

read_text(path: str, encoding: str = 'utf-8') -> Optional[str]

Read a text file.

Parameters:

Name Type Description Default
path str

Absolute path or path relative to app_dir.

required
encoding str

Text encoding (default "utf-8").

'utf-8'

Returns:

Type Description
Optional[str]

File contents as a str, or None if the file cannot be

Optional[str]

read.

write_text staticmethod

write_text(path: str, content: str, encoding: str = 'utf-8') -> bool

Write a text file, creating parent directories as needed.

Parameters:

Name Type Description Default
path str

Absolute or app_dir-relative path.

required
content str

String to write.

required
encoding str

Text encoding (default "utf-8").

'utf-8'

Returns:

Type Description
bool

True on success, False on OSError.

exists staticmethod

exists(path: str) -> bool

Return whether a file or directory exists.

Parameters:

Name Type Description Default
path str

Absolute or app_dir-relative path.

required

Returns:

Type Description
bool

True if the path exists.

delete staticmethod

delete(path: str) -> bool

Delete a single file.

Parameters:

Name Type Description Default
path str

Absolute or app_dir-relative path.

required

Returns:

Type Description
bool

True on success, False on OSError.

list_dir staticmethod

list_dir(path: str = '') -> list

List the entries in a directory.

Parameters:

Name Type Description Default
path str

Absolute or app_dir-relative path. Defaults to the app data directory itself.

''

Returns:

Type Description
list

A list of entry names, or an empty list on error.

read_bytes staticmethod

read_bytes(path: str) -> Optional[bytes]

Read a binary file.

Parameters:

Name Type Description Default
path str

Absolute or app_dir-relative path.

required

Returns:

Type Description
Optional[bytes]

File contents as bytes, or None if the file cannot be

Optional[bytes]

read.

write_bytes staticmethod

write_bytes(path: str, data: bytes) -> bool

Write a binary file, creating parent directories as needed.

Parameters:

Name Type Description Default
path str

Absolute or app_dir-relative path.

required
data bytes

Bytes to write.

required

Returns:

Type Description
bool

True on success, False on OSError.

get_size staticmethod

get_size(path: str) -> Optional[int]

Return file size in bytes.

Parameters:

Name Type Description Default
path str

Absolute or app_dir-relative path.

required

Returns:

Type Description
Optional[int]

File size in bytes, or None if the file is missing or

Optional[int]

unreadable.

ensure_dir staticmethod

ensure_dir(path: str) -> bool

Create a directory (and any missing parents) idempotently.

Parameters:

Name Type Description Default
path str

Absolute or app_dir-relative path.

required

Returns:

Type Description
bool

True on success or if the directory already exists.

join staticmethod

join(*parts: Any) -> str

Join path components using the OS separator.

Equivalent to os.path.join(*map(str, parts)). Provided as a convenience so callers do not need to import os.path directly.

Parameters:

Name Type Description Default
*parts Any

Path components (each coerced to str).

()

Returns:

Type Description
str

The joined path string.

Notifications

Cross-platform local notifications.

Provides coroutines for requesting permission and scheduling / cancelling local push notifications. Uses Android's NotificationManager or iOS's UNUserNotificationCenter.

On iOS you must await Notifications.request_permission() before scheduling. On Android 13+ the runtime permission should be requested through standard Android APIs (the manifest declaration is otherwise sufficient).

Example
import pythonnative as pn

async def setup_reminders():
    if not await pn.Notifications.request_permission():
        return
    await pn.Notifications.schedule(
        title="Reminder",
        body="Time for a walk!",
        delay_seconds=60,
        identifier="walk",
    )

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.

request_permission async staticmethod

request_permission() -> bool

Request notification permission from the user.

On Android the manifest declaration is normally sufficient for legacy permission grants and this returns True without prompting (the runtime POST_NOTIFICATIONS prompt for Android 13+ should be requested via standard Android APIs).

Returns:

Type Description
bool

True if granted (or no prompt is needed), False

bool

otherwise.

schedule async staticmethod

schedule(title: str, body: str = '', *, delay_seconds: float = 0, identifier: str = 'default', **options: Any) -> 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 for an effectively immediate notification.

0
identifier str

Stable ID used by cancel to target this notification.

'default'
**options Any

Reserved for future tuning (e.g., sound, badge, category).

{}

Returns:

Type Description
bool

True on success, False if the underlying native

bool

call failed.

cancel async staticmethod

cancel(identifier: str = 'default') -> None

Cancel a pending notification by its identifier.

Parameters:

Name Type Description Default
identifier str

The same string passed to schedule.

'default'

Clipboard

Cross-platform clipboard access.

Clipboard reads and writes the system pasteboard. All methods are synchronous: UIPasteboard (iOS) and ClipboardManager (Android) both answer immediately, so there's no need for a coroutine.

On a desktop machine (neither Android nor iOS) the module falls back to a process-local string buffer. That keeps it usable in the desktop mock target and unit tests instead of raising.

Example
import pythonnative as pn

pn.Clipboard.set_string("hello")
assert pn.Clipboard.get_string() == "hello"

Classes:

Name Description
Clipboard

System clipboard interface (synchronous).

Clipboard

System clipboard interface (synchronous).

Methods:

Name Description
set_string

Copy text onto the system clipboard.

get_string

Return the current clipboard string ("" when empty).

has_string

Return True when the clipboard holds non-empty text.

set_string staticmethod

set_string(text: str) -> None

Copy text onto the system clipboard.

get_string staticmethod

get_string() -> str

Return the current clipboard string ("" when empty).

has_string staticmethod

has_string() -> bool

Return True when the clipboard holds non-empty text.

Share

Present the system share sheet.

Share.share is a coroutine that opens UIActivityViewController (iOS) or an ACTION_SEND chooser (Android) and resolves to True once the user completes a share or False if they dismiss it.

Example
import pythonnative as pn

async def share_link():
    await pn.Share.share(
        message="Check out PythonNative!",
        url="https://example.com",
    )

Classes:

Name Description
Share

System share-sheet interface.

Share

System share-sheet interface.

Methods:

Name Description
share

Open the share sheet with message / url.

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 message on Android).

None
title Optional[str]

Chooser title (Android) / subject (iOS mail).

None

Returns:

Type Description
bool

True if the user completed a share, False if they

bool

cancelled or no share UI is available.

Linking

Open URLs, deep links, and the system settings page.

Linking wraps UIApplication.openURL / Intent(ACTION_VIEW) so a Python app can hand a URL (https:, mailto:, tel:, a custom scheme, …) to the OS.

All methods are synchronous and return a bool describing whether the platform accepted the request. On desktop they return False.

Example
import pythonnative as pn

if pn.Linking.can_open_url("tel:+15551234567"):
    pn.Linking.open_url("tel:+15551234567")

Classes:

Name Description
Linking

System URL / deep-link interface (synchronous).

Functions:

Name Description
set_initial_url

Record the launch URL (called by the native host on cold start).

Linking

System URL / deep-link interface (synchronous).

Methods:

Name Description
open_url

Hand url to the OS. Returns True if it was accepted.

can_open_url

Return True when some installed app can handle url.

open_settings

Open this app's entry in the system Settings app.

get_initial_url

Return the URL that launched the app, if any.

open_url staticmethod

open_url(url: str) -> bool

Hand url to the OS. Returns True if it was accepted.

can_open_url staticmethod

can_open_url(url: str) -> bool

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

get_initial_url() -> Optional[str]

Return the URL that launched the app, if any.

set_initial_url

set_initial_url(url: Optional[str]) -> None

Record the launch URL (called by the native host on cold start).

Permissions

Runtime permission checks and requests.

Permissions normalizes the very different iOS and Android permission models behind two calls:

  • check(permission) — synchronous, returns a status string without prompting.
  • request(permission) — a coroutine that 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".

Supported permission names: "camera", "microphone", "location", "photos", "notifications", "contacts". Unknown names resolve to "undetermined".

Classes:

Name Description
Permissions

Runtime permission interface.

Functions:

Name Description
deliver_android_permission_result

Forward an onRequestPermissionsResult to the pending coroutine.

Permissions

Runtime permission interface.

Methods:

Name Description
check

Return the current status of permission without prompting.

request

Prompt for permission (if needed) and return the result.

check staticmethod

check(permission: PermissionName) -> PermissionStatus

Return the current status of permission without prompting.

request async staticmethod

request(permission: PermissionName) -> PermissionStatus

Prompt for permission (if needed) and return the result.

deliver_android_permission_result

deliver_android_permission_result(request_code: int, permissions: Any, grant_results: Any) -> bool

Forward an onRequestPermissionsResult to the pending coroutine.

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 host (the iOS app delegate / Android Activity) forwards lifecycle callbacks by calling dispatch_app_state, so the same listener machinery works on every platform and in tests.

Prefer the use_app_state hook inside components; use the imperative API for non-UI code.

Example
import pythonnative as pn

@pn.component
def Banner():
    state = pn.use_app_state()
    return pn.Text(f"App is {state}")

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.

AppState

App lifecycle state interface.

Methods:

Name Description
current_state

Return the current lifecycle phase.

add_listener

Subscribe to lifecycle changes.

current_state staticmethod

current_state() -> AppStateStatus

Return the current lifecycle phase.

add_listener staticmethod

add_listener(callback: Callable[[AppStateStatus], None]) -> Callable[[], None]

Subscribe to lifecycle changes.

Returns:

Type Description
Callable[[], None]

A zero-arg function that unsubscribes when called.

dispatch_app_state

dispatch_app_state(state: AppStateStatus) -> None

Update the current state and notify every listener.

Called by the native host on lifecycle transitions. Unknown values are ignored so a misbehaving host can't push garbage into the tree.

use_app_state

use_app_state() -> AppStateStatus

Subscribe a component to AppState.

Returns:

Type Description
AppStateStatus

The current lifecycle phase; the component re-renders whenever

AppStateStatus

it changes.

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 as the native host forwards connectivity changes 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.

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.

fetch staticmethod

fetch() -> NetInfoState

Return a fresh snapshot of connectivity state.

add_listener staticmethod

add_listener(callback: Callable[[NetInfoState], None]) -> Callable[[], None]

Subscribe to connectivity changes; returns an unsubscribe fn.

dispatch_net_info

dispatch_net_info(state: NetInfoState) -> None

Push a new connectivity snapshot and notify listeners.

use_net_info

use_net_info() -> NetInfoState

Subscribe a component to NetInfo.

Returns:

Type Description
NetInfoState

The latest connectivity snapshot dict; the component

NetInfoState

re-renders whenever connectivity changes.

Secure storage

Encrypted key/value storage for secrets (tokens, credentials).

SecureStore persists small string values in the iOS Keychain and Android EncryptedSharedPreferences — the right place for auth tokens and other secrets that AsyncStorage (plain, unencrypted) should never hold.

All methods are synchronous and return a bool (writes/deletes) or Optional[str] (reads). On desktop the module falls back to an in-process dict so code paths stay exercisable without a device Keychain.

Example
import pythonnative as pn

pn.SecureStore.set_item("token", "abc123")
token = pn.SecureStore.get_item("token")

Classes:

Name Description
SecureStore

Encrypted secret storage (synchronous).

SecureStore

Encrypted secret storage (synchronous).

Methods:

Name Description
set_item

Store value under key. Returns True on success.

get_item

Return the value for key, or None if absent.

delete_item

Delete key. Returns True if it existed and was removed.

set_item staticmethod

set_item(key: str, value: str) -> bool

Store value under key. Returns True on success.

get_item staticmethod

get_item(key: str) -> Optional[str]

Return the value for key, or None if absent.

delete_item staticmethod

delete_item(key: str) -> bool

Delete key. Returns True if it existed and was removed.

Battery

Battery level and charging state.

Battery reports the current charge fraction (0.01.0, or -1.0 when unknown) and charging state, and lets you subscribe to changes that the native host forwards via dispatch_battery.

Classes:

Name Description
Battery

Battery interface (synchronous getters + change listener).

Functions:

Name Description
dispatch_battery

Notify listeners of a battery change (called by the native host).

Battery

Battery interface (synchronous getters + change listener).

Methods:

Name Description
get_level

Return the charge fraction in [0, 1] (-1.0 if unknown).

get_state

Return "charging" / "full" / "unplugged" / "unknown".

add_listener

Subscribe to battery changes; returns an unsubscribe fn.

get_level staticmethod

get_level() -> float

Return the charge fraction in [0, 1] (-1.0 if unknown).

get_state staticmethod

get_state() -> BatteryState

Return "charging" / "full" / "unplugged" / "unknown".

add_listener staticmethod

add_listener(callback: Callable[[Dict[str, object]], None]) -> Callable[[], None]

Subscribe to battery changes; returns an unsubscribe fn.

Each callback receives {"level": float, "state": str}.

dispatch_battery

dispatch_battery(level: float, state: BatteryState) -> None

Notify listeners of a battery change (called by the native host).

Haptics & vibration

Haptic feedback and raw vibration.

Two interfaces live here:

  • Haptics — semantic, iOS-style feedback (impact / notification / selection) backed by UIFeedbackGenerator on iOS and VibrationEffect patterns on Android.
  • Vibration — a blunt "buzz for N milliseconds" interface for cases where you want an explicit duration.

Every method is synchronous and best-effort: on a device that lacks a Taptic Engine / vibrator, or on desktop, calls are silent no-ops rather than errors.

Classes:

Name Description
Haptics

Semantic haptic feedback (synchronous, best-effort).

Vibration

Raw vibration control (synchronous, best-effort).

Haptics

Semantic haptic feedback (synchronous, best-effort).

Methods:

Name Description
impact

Play a physical "impact" tap of the given style.

notification

Play a success / warning / error notification pattern.

selection

Play the light "selection changed" tick.

impact staticmethod

impact(style: ImpactStyle = 'medium') -> None

Play a physical "impact" tap of the given style.

notification staticmethod

notification(type_: NotificationType = 'success') -> None

Play a success / warning / error notification pattern.

selection staticmethod

selection() -> None

Play the light "selection changed" tick.

Vibration

Raw vibration control (synchronous, best-effort).

Methods:

Name Description
vibrate

Vibrate for duration_ms milliseconds.

cancel

Cancel an in-progress vibration (Android only).

vibrate staticmethod

vibrate(duration_ms: int = 400) -> None

Vibrate for duration_ms milliseconds.

cancel staticmethod

cancel() -> None

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).

is_available is synchronous; authenticate is a coroutine that presents the system prompt and resolves to True on success or False on failure / cancellation.

Example
import pythonnative as pn

async def unlock():
    if await pn.Biometrics.authenticate("Unlock your vault"):
        show_secrets()

Classes:

Name Description
Biometrics

Biometric authentication interface.

Biometrics

Biometric authentication interface.

Methods:

Name Description
is_available

Return True when biometric auth can be attempted.

authenticate

Present the biometric prompt; resolve True on success.

is_available staticmethod

is_available() -> bool

Return True when biometric auth can be attempted.

authenticate async staticmethod

authenticate(reason: str = 'Authenticate') -> bool

Present the biometric prompt; resolve True on success.

Next steps