Skip to content

Architecture

PythonNative maps Python directly to native platform APIs. Conceptually, it is closer to NativeScript's dynamic bindings than to React Native's bridge-and-module approach.

High-level model

  • Direct bindings: call native APIs synchronously from Python.
  • iOS: rubicon-objc exposes Objective-C/Swift classes (e.g., UIViewController, UIButton, WKWebView) and lets you create dynamic Objective-C subclasses and selectors.
  • Android: Chaquopy exposes Java classes (e.g., android.widget.Button, android.webkit.WebView) via the java bridge so you can construct and call methods directly.
  • Shared Python API: components like Page, StackView, Label, Button, and WebView have a small, consistent surface. Platform-specific behavior is chosen at import time using pythonnative.utils.IS_ANDROID.
  • Thin native bootstrap: the host app remains native (Android Activity or iOS UIViewController). It passes a live instance/pointer into Python, and Python drives the UI from there.

Comparison

  • Versus React Native: RN typically exposes capabilities via native modules/TurboModules and a bridge. PythonNative does not require authoring such modules for most APIs; you can access platform classes directly from Python.
  • Versus NativeScript: similar philosophy—dynamic, synchronous access to Obj-C/Java from the scripting runtime.

iOS flow (Rubicon-ObjC)

  • The iOS template (Swift + PythonKit) boots Python and calls your bootstrap(native_instance) with the UIViewController pointer.
  • In Python, Rubicon wraps the pointer; you then interact with UIKit classes directly.
from rubicon.objc import ObjCClass, ObjCInstance

UIButton = ObjCClass("UIButton")
vc = ObjCInstance(native_ptr)  # passed from Swift template
button = UIButton.alloc().init()
# Configure target/action via a dynamic Objective-C subclass (see Button implementation)

Android flow (Chaquopy)

  • The Android template (Kotlin + Chaquopy) initializes Python in MainActivity and provides the current Activity/Context to Python.
  • Components acquire the Context implicitly and construct real Android views.
from java import jclass
from pythonnative.utils import get_android_context

WebViewClass = jclass("android.webkit.WebView")
context = get_android_context()
webview = WebViewClass(context)
webview.loadUrl("https://example.com")

Key implications

  • Synchronous native calls: no JS bridge; Python calls are direct.
  • Lifecycle rules remain native: Activities/ViewControllers are created by the OS. Python receives and controls them; it does not instantiate Android Activities directly.
  • Small, growing surface: the shared Python API favors clarity and consistency, expanding progressively.
  • Guides / Android: guides/android.md
  • Guides / iOS: guides/ios.md
  • Concepts / Components: concepts/components.md