FazBrowse GitHub Viewer | Trending |
URL:
| Home
Tools: [Download Repo ZIP]   [Original HTTPS Page]

feat!: add pythonnative.toml config and build system by owenthcarey · Pull Request #10 · pythonnative/pythonnative · GitHub

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension .json  (2) .md  (14) .py  (19) .sh  (1) .toml  (3) .txt  (2) .yaml  (3) .yml  (1) All 8 file types selected
Only manifest files
Deleted files Viewed files
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Unified
Split
Hide whitespace
Diff view
Unified
Split
Hide whitespace
10 changes: 9 additions & 1 deletion docs/api/cli.md
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,21 @@ the documented behavior never drifts from the code.
## Subcommands

- `pn init [name]`: scaffold a new project (creates `app/`,
`pythonnative.json`, `requirements.txt`, `.gitignore`).
`pythonnative.toml`, `.gitignore`). Flag: `--force` to overwrite
existing files. See [Configuration](../guides/configuration.md).
- `pn doctor [android|ios]`: diagnose the local toolchain and validate
`pythonnative.toml`. Exits non-zero when something will block a build.
- `pn preview [component]`: render the app in a desktop (Tkinter) window
with Fast Refresh — the fastest way to iterate on UI. Flags:
`--width`, `--height`, `--title`, `--no-hot-reload`. See the
[Desktop preview guide](../guides/desktop-preview.md).
- `pn run android|ios`: build and run on a connected device or
simulator. Flags: `--prepare-only`, `--hot-reload`, `--no-logs`.
- `pn build android|ios`: build distributable artifacts (release by
default). Flag: `--debug` for the debug variant. See
[Building for release](../guides/building-for-release.md).
- `pn app-id android|ios`: print the resolved application id (Android)
or bundle id (iOS) — handy for scripts and CI.
- `pn clean`: remove the local `build/` directory.

::: pythonnative.cli.pn
Expand Down
4 changes: 2 additions & 2 deletions docs/concepts/components.md
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
Original file line number Diff line number Diff line change
Expand Up @@ -187,8 +187,8 @@ def App():
The entry point [`create_screen`][pythonnative.create_screen] is called
internally by native templates to bootstrap your root component. You
don't call it directly: name your top-level component `App` (so the
templates can find it by convention) and `pythonnative.json` points
at the module that defines it.
templates can find it by convention) and `app.entry_point` in
`pythonnative.toml` points at the module that defines it.

## State and re-rendering

Expand Down
63 changes: 61 additions & 2 deletions docs/getting-started.md
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,9 @@ pn init MyApp
This scaffolds:

- `app/` with a minimal `main.py`
- `pythonnative.json` project config
- `requirements.txt`
- `pythonnative.toml` — your project configuration: app id, version,
permissions, assets, and signing. See
[Configuration](guides/configuration.md).
- `.gitignore`

A minimal `app/main.py` looks like:
Expand Down Expand Up @@ -66,6 +67,34 @@ Key ideas:

When the root `Stack.Navigator` is rendered inside the host's first screen, `navigate(...)` and `go_back()` drive the **native** navigation controller (UINavigationController on iOS, AndroidX Navigation Component on Android). Each pushed screen runs in its own reconciler host, so state on the previous screen is preserved by the platform stack.

## Configure your app

Everything about your app's *identity* — its bundle/application id,
display name, version, the device permissions it requests, its icon and
splash, third-party packages, and signing — lives in a single
`pythonnative.toml` at the project root:

```toml
[app]
id = "com.example.myapp"
name = "myapp"
display_name = "My App"
version = "1.0.0"
build = 1

[permissions]
camera = "Scan receipts with your camera."
notifications = true

[assets]
icon = "assets/icon.png"
```

The build system reads this file for every command, so `pn run`,
`pn build`, `pn doctor`, and `pn app-id` all stay in sync. See the full
[Configuration reference](guides/configuration.md) and the
[Permissions guide](guides/permissions.md).

## Preview on your desktop

The fastest way to iterate is `pn preview`, which renders your app in a
Expand Down Expand Up @@ -177,6 +206,36 @@ pn run android --no-logs
pn run ios --no-logs
```

## Check your toolchain

Before your first build, run `pn doctor` to verify the local toolchain
(Java/Android SDK for Android; Xcode/Simulator and a signing team for
iOS) and validate your `pythonnative.toml`:

```bash
pn doctor # check everything
pn doctor android # only Android-relevant checks
pn doctor ios # only iOS-relevant checks
```

It prints `[ok]` / `[!]` / `[x]` for each check and exits non-zero when
something will block a build, so it's safe to run in CI.

## Build for release

When you're ready to ship, `pn build` produces signed, distributable
artifacts:

```bash
pn build android # release APK + AAB
pn build ios # signed .ipa via xcodebuild archive/export
```

Release builds need signing configured in `pythonnative.toml` (a
keystore for Android, a development team for iOS). See
[Building for release](guides/building-for-release.md) for the full
walkthrough.

## Clean

Remove the build artifacts safely:
Expand Down
2 changes: 1 addition & 1 deletion docs/guides/android.md
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ The native Android template uses
[`create_screen`][pythonnative.create_screen] internally to bootstrap your
root component inside a `ScreenFragment`. You don't call `create_screen`
directly; just export your component and configure the entry point in
`pythonnative.json`.
`pythonnative.toml` (`app.entry_point`).

## Run

Expand Down
216 changes: 216 additions & 0 deletions docs/guides/building-for-release.md
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
Original file line number Diff line number Diff line change
@@ -0,0 +1,216 @@
# Building for release

`pn run` is for iterating on a device or simulator. When you're ready to
ship, `pn build` produces standalone, distributable artifacts:

```bash
pn build android # release APK + AAB
pn build ios # signed .ipa via xcodebuild archive + export
```

Pass `--debug` to build the debug variant instead (a debug APK on
Android; a Simulator `.app` on iOS):

```bash
pn build android --debug
pn build ios --debug
```

`pn build` reads identity, permissions, assets, and signing from
[`pythonnative.toml`](configuration.md). Run [`pn doctor`](#check-first-pn-doctor)
first to confirm the toolchain is ready.

---

## Check first: `pn doctor`

```bash
pn doctor android
pn doctor ios
```

`pn doctor` validates `pythonnative.toml` and checks the platform
toolchain — for Android: `adb`, a JDK, and whether release signing is
configured; for iOS: macOS, Xcode, `simctl`, and a development team. It
exits non-zero on anything that will block a build, so you can gate CI
on it.

---

## Android

`pn build android` runs `assembleRelease` and `bundleRelease`, producing
both an APK and a Play-ready AAB. Artifacts are reported at the end of
the build and live under the staged project:

```
build/android/android_template/app/build/outputs/apk/release/app-release.apk
build/android/android_template/app/build/outputs/bundle/release/app-release.aab
```

### Signing

Without signing configured, Gradle emits an **unsigned** release APK
(`app-release-unsigned.apk`) — fine for inspection, not for the store.
To produce signed artifacts, create a keystore once:

```bash
keytool -genkeypair -v -keystore release.keystore \
-alias myapp -keyalg RSA -keysize 2048 -validity 10000
```

…then point `pythonnative.toml` at it:

```toml
[android.signing]
keystore = "release.keystore"
key_alias = "myapp"
# store_password_env / key_password_env default to
# PN_ANDROID_KEYSTORE_PASSWORD / PN_ANDROID_KEY_PASSWORD
```

Passwords are **never** stored in the config — only the names of the
environment variables that hold them. Provide the secrets at build time:

```bash
export PN_ANDROID_KEYSTORE_PASSWORD=…
export PN_ANDROID_KEY_PASSWORD=…
pn build android
```

When signing is configured, `pn` injects a Gradle `signingConfig` into
the release build so the resulting APK/AAB are signed and upload-ready.

!!! tip "Keep keystores out of git"
Commit neither the keystore nor the passwords. Store the keystore as
a CI secret/file and inject the passwords via environment variables.

---

## iOS

`pn build ios` archives the app for a device with `xcodebuild archive`,
embeds the device CPython slice into the archive, and exports a signed
`.ipa` with `xcodebuild -exportArchive`. Outputs:

```
build/ios/ios_template/build/export/*.ipa
build/ios/ios_template/build/ios_template.xcarchive
```

!!! warning "Experimental"
The device archive/export path embeds and re-signs the embedded
Python framework. Treat it as experimental and verify on a real
device before relying on it for store submission.

### Signing

Set your Apple Developer Team ID and an export method:

```toml
[ios]
development_team = "ABCDE12345"

[ios.signing]
export_method = "app-store" # development | ad-hoc | app-store | enterprise
provisioning_profile = "My App Distribution"
```

`development_team` drives signing during `archive`; `export_method` and
the optional `provisioning_profile` are written into the
`exportOptions.plist` that `xcodebuild -exportArchive` consumes. If
export fails, the error points you back at `[ios.signing]`.

### Embedded Python runtime

iOS has no system Python, so PythonNative embeds CPython from the
[Python-Apple-support](https://github.com/beeware/Python-Apple-support)
project. On the first iOS build, `pn` downloads the pinned, checksum-
verified runtime for your `app.python_version` and caches it under
`build/ios/ios_runtime/`. The correct slice (Simulator vs. device) is
embedded into the app bundle along with the standard library, your
`app/` sources, the bundled `pythonnative` package, and any pure-Python
`[requirements].packages`.

iOS currently ships a verified runtime for **Python 3.11**; set
`python_version = "3.11"` in `[app]` for device builds.

---

## App icon and splash

Provide a single high-resolution source image and PythonNative renders
every per-platform, per-density variant at build time:

```toml
[assets]
icon = "assets/icon.png" # 1024x1024 PNG
splash = "assets/splash.png"
```

- **iOS** — a universal `AppIcon.appiconset` (Xcode resizes the rest)
and a `Splash` image set referenced by the generated launch screen.
- **Android** — `mipmap-*` launcher icons at every density plus a round
variant, and a centered icon for the Android 12+ splash screen.

Image processing needs [Pillow](https://python-pillow.org/), an optional
dependency:

```bash
pip install 'pythonnative[build]'
```

If Pillow isn't installed the build still succeeds — it just keeps the
template's default assets. `pn doctor` reports whether Pillow is
available.

---

## Versioning

Two fields in `[app]` drive the store-visible version and the internal
build number:

```toml
[app]
version = "1.2.0" # CFBundleShortVersionString / versionName
build = 7 # CFBundleVersion / versionCode (bump every upload)
```

Both stores reject a new upload that reuses an existing build number, so
increment `build` for each submission.

---

## Continuous integration

A typical release job:

```bash
pip install 'pythonnative[build]'
pn doctor android # fail fast on a misconfigured runner
export PN_ANDROID_KEYSTORE_PASSWORD=$KEYSTORE_PW
export PN_ANDROID_KEY_PASSWORD=$KEY_PW
pn build android
```

`pn app-id android` / `pn app-id ios` print the resolved id, which is
handy for downstream steps (uploaders, smoke tests) that need it without
re-parsing the config.

---

## Prepare without building

To hand off to Android Studio or Xcode instead of building from the CLI,
stage and configure the native project without compiling:

```bash
pn run android --prepare-only
pn run ios --prepare-only
```

This writes a fully configured project (identity, permissions, icons,
relocated Android package) under `build/`, which you can open and build
with the native IDE — useful for debugging signing or build issues with
the platform's own tooling.
Loading
Loading

Back | FazBrowse Home | New Git URL