Metadata-Version: 2.5
Name: kivy-reloader
Version: 0.9.114
Summary: Hot reload your Kivy app on multiple Android phones and computer in real-time.
Project-URL: Homepage, https://kivyschool.com/kivy-reloader/
Project-URL: Repository, https://github.com/kivy-school/kivy-reloader
Author-email: filipemarch <filipe.marchesini@gmail.com>, 138998466+AccelQuasarDragon@users.noreply.github.com
License: MIT
License-File: LICENSE
Requires-Python: >=3.10
Requires-Dist: tomlkit>=0.13.3
Requires-Dist: trio>=0.30.0
Provides-Extra: desktop
Requires-Dist: buildozer>=1.5.0; extra == 'desktop'
Requires-Dist: colorama>=0.4.6; extra == 'desktop'
Requires-Dist: cython>=3.1.2; extra == 'desktop'
Requires-Dist: kaki>=0.1.9; extra == 'desktop'
Requires-Dist: keyring>=25.0.0; extra == 'desktop'
Requires-Dist: kivy>=2.3.1; extra == 'desktop'
Requires-Dist: pip>=25.1.1; extra == 'desktop'
Requires-Dist: plyer>=2.1.0; extra == 'desktop'
Requires-Dist: psutil>=7.0.0; extra == 'desktop'
Requires-Dist: pygithub>=2.0.0; extra == 'desktop'
Requires-Dist: pyobjus>=1.2.0; (sys_platform == 'darwin') and extra == 'desktop'
Requires-Dist: readchar>=4.2.1; extra == 'desktop'
Requires-Dist: requests>=2.32.0; extra == 'desktop'
Requires-Dist: setuptools>=75.0; (python_version >= '3.12') and extra == 'desktop'
Requires-Dist: typer>=0.16.0; extra == 'desktop'
Description-Content-Type: text/markdown

# Kivy Reloader

> _Hot reload your Kivy app on multiple Android phones, emulators and computer at the same time, in real‑time._

<p align="center">
  <img src="https://kivyschool.com/kivy-reloader/assets/kivy-reloader.gif" alt="Kivy Reloader Demo" width="720" />
</p>

[![Watch the video](https://img.youtube.com/vi/UiuSkGHWvWc/maxresdefault.jpg)](https://youtu.be/UiuSkGHWvWc)

This tool allows you to instantly update your Kivy app on multiple devices simultaneously by pressing <kbd>Ctrl</kbd> + <kbd>S</kbd>, without having to restart / recompile every time you make a change, saving your precious development time and effort.
It uses **[Kaki]** (file watching via `watchdog`) under the hood and a small **Trio** server on-device to receive file updates.

Check out the [📚 Kivy School tutorial](https://kivyschool.com/kivy-reloader/) to learn how to use this tool, or follow the documentation below.

- 📚 Full docs: **[https://kivyschool.com/kivy-reloader/](https://kivyschool.com/kivy-reloader/)**
- Install: [https://kivyschool.com/kivy-reloader/installation/](https://kivyschool.com/kivy-reloader/installation/)
- How to use: [https://kivyschool.com/kivy-reloader/how-to-use/](https://kivyschool.com/kivy-reloader/how-to-use/)

---

## Quickstart

### 1) Install the toolchain + helpers

Pick your OS and run the one‑liners below. These scripts set up the Android toolchain, `uv`, Buildozer deps, scrcpy, bundletool, etc.

#### Linux

```bash
curl -LsSf https://kivyschool.com/kivy-android-ubuntu.sh | bash
```

#### macOS
[![Watch the video](https://img.youtube.com/vi/yDhIwEMg1VE/maxresdefault.jpg)](https://youtu.be/yDhIwEMg1VE)

> After installing Homebrew, **close & reopen** the terminal so `brew` is in PATH.

```bash
# Install Homebrew (if needed)
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"

# System deps + OpenJDK 17 and symlink so macOS tools can find it
brew install android-platform-tools openjdk@17 autoconf automake libtool pkg-config cmake openssl
sudo ln -sfn $(brew --prefix openjdk@17)/libexec/openjdk.jdk \
  /Library/Java/JavaVirtualMachines/openjdk-17.jdk

# Kivy Reloader setup
curl -LsSf https://kivyschool.com/kivy-android-macos.sh | sh
```

#### Windows

[![Watch the video](https://img.youtube.com/vi/fQfUx5eXBMQ/maxresdefault.jpg)](https://youtu.be/fQfUx5eXBMQ)


Run **PowerShell as Administrator**:

```powershell
# Base setup (scrcpy + adb init)
powershell -ExecutionPolicy ByPass -c "irm https://kivyschool.com/kivy-android-windows.ps1 | iex"

# Install WSL2 + Ubuntu 24.04
wsl --install -d Ubuntu-24.04
```

Then, inside the new **Ubuntu** terminal:

```bash
curl -LsSf https://kivyschool.com/kivy-android-wsl2.sh | bash
```

---

### 2) Create a tiny demo project (pick one)

#### Beginner (single file)

```bash
mkdir kivyschool-hello
cd kivyschool-hello
uv init
uv add --dev "kivy-reloader[desktop]>=0.9.112"
```

Project tree:

```
kivyschool-hello
├── main.py
├── pyproject.toml
├── README.md
└── uv.lock
```

`main.py`

```python
import trio
from kivy.lang import Builder
from kivy_reloader.app import App

kv = """
Button:
    text: "Hello World"
"""


class MainApp(App):
    def build(self):
        return Builder.load_string(kv)


app = MainApp()
trio.run(app.async_run, 'trio')
```

#### Advanced (recommended package structure)

```bash
mkdir -p kivyschool-hello/hello_world/screens
cd kivyschool-hello
uv init
uv add --dev "kivy-reloader[desktop]>=0.9.112"
```

Project tree:

```
kivyschool-hello
├── hello_world
│   ├── app.py
│   └── screens
│       ├── main_screen.py
│       └── main_screen.kv
├── main.py
├── pyproject.toml
├── README.md
└── uv.lock
```

`main.py`

```python
import trio
from hello_world import HelloWorldApp

app = HelloWorldApp()
trio.run(app.async_run, 'trio')
```

`hello_world/app.py`

```python
from kivy_reloader.app import App
from hello_world.screens.main_screen import MainScreen


class HelloWorldApp(App):
    def build(self):
        return MainScreen()
```

`hello_world/screens/main_screen.kv`

```yaml
<MainScreen>:
  BoxLayout:
    orientation: "vertical"
    Button:
      text: "Welcome to Kivy Reloader!"
```

`hello_world/screens/main_screen.py`

```python
from kivy.uix.screenmanager import Screen
from kivy_reloader.lang import Builder

Builder.load_file(__file__)


class MainScreen(Screen):
    pass
```

---

### 3) Initialize Kivy Reloader in your project

```bash
uv run kivy-reloader init
```

This creates **`kivy-reloader.toml`** (config) and a minimal **`buildozer.spec`**.

<p align="center">
  <img src="https://kivyschool.com/kivy-reloader/assets/kivy-reloader-init.png" alt="kivy-reloader init" width="720" />
</p>

**Minimal config example:**

```toml
[kivy_reloader]
HOT_RELOAD_ON_PHONE = true
FULL_RELOAD_FILES = ["main.py"]
WATCHED_FOLDERS_RECURSIVELY = ["."]
STREAM_USING = "USB"  # or "WIFI" (requires initial cable setup)
```

---

## Usage

### Step 1 — Run on your computer

```bash
uv run main.py
```

This starts your app and the reloader background watcher.

### Step 2 — Deploy to Android

```bash
uv run kivy-reloader run
```

<p align="center">
  <img src="https://kivyschool.com/kivy-reloader/assets/kivy-reloader-run.png" alt="kivy-reloader run" width="720" />
</p>

Select the first option to build + install the APK via Buildozer. Once running on your phone, hot reload is already active.

### Step 3 — Develop with hot reload ♻️

When you save a watched file:

- If it matches **`FULL_RELOAD_FILES`** → the app **restarts** on computer and device(s).
- If it's inside **`WATCHED_FOLDERS_RECURSIVELY`**, **`WATCHED_FOLDERS`** or named in **`WATCHED_FILES`** → the app **hot reloads**.
- With **`HOT_RELOAD_ON_PHONE = false`** only your desktop app reloads/restarts.

---

## Build APK via GitHub Actions

Build your APK on GitHub's servers — no local Buildozer install needed. Flightdeck downloads the finished APK and installs it on your phone automatically.

### Step 1 — Workflow file

`kivy-reloader init project` creates `.github/workflows/build-apk.yml` automatically. If it's missing, create it manually:

```yaml
name: Build APK

on:
  workflow_dispatch:

jobs:
  build:
    runs-on: ubuntu-latest
    container: kivy/buildozer
    steps:
      - uses: actions/checkout@v6

      - name: Cache buildozer
        uses: actions/cache@v6
        with:
          path: |
            .buildozer
            /github/home/.buildozer
          key: buildozer-${{ hashFiles('buildozer.spec') }}
          restore-keys: buildozer-

      - run: yes | buildozer android debug

      - uses: actions/upload-artifact@v7
        with:
          name: app-debug.apk
          path: bin/*.apk
```

### Step 2 — Add `[github]` to your `kivy-reloader.toml`

```toml
[github]
repo = "your-username/your-repo"
workflow = "build-apk.yml"
```

### Step 3 — Click Build APK in Flightdeck

Open Flightdeck → Quick Commands → **Build APK (GitHub)**. On first use you'll be asked to authenticate with GitHub (one-time only). After that:

1. GitHub Actions triggers the build on their servers (~10–15 min)
2. Flightdeck polls until the run completes
3. APK downloads automatically
4. Installs on your connected phone via ADB
5. scrcpy + logcat start immediately
6. First build is around ~10-15min. The process after the first build takes ~3 minutes.

> **Tip:** If your build fails with `charset_normalizer` wheel errors, add `charset-normalizer==2.1.1` to your `buildozer.spec` requirements.

> **Security:** GitHub tokens are stored in your OS keychain (Windows Credential Manager, macOS Keychain, Linux libsecret) when available. If the keychain is unavailable, tokens fall back to `~/.config/kivy-reloader/credentials.toml`.

---

## How it works (high level)

- Watches files using **watchdog** (via **Kaki**).
- On change, syncs files and signals your app(s) to reload.
- An on‑device Trio server receives files during development for instant updates.

---

## Running kivy-reloader from a local editable clone (dev / contributor setup)

Use this when you want to test changes to kivy-reloader itself — the desktop app, Flightdeck, build logic, etc. — against a real project without publishing to PyPI.

```bash
cd ~
mkdir reloadtest && cd reloadtest

uv init --python 3.13
uv add "kivy>=2.3.1"
git clone --branch macfix_gaimwsl https://github.com/kivy-school/kivy-reloader
uv add --editable "./kivy-reloader[desktop]"
uv run kivy-reloader init project
```

**To also test on the phone** (so the phone app picks up your local changes too), add the local path to `buildozer.spec` requirements:

```
# buildozer.spec
requirements = python3,kivy==2.3.0,...,git+file:///home/youruser/reloadtest/kivy-reloader
```

Replace `/home/youruser/reloadtest/kivy-reloader` with the path to your local clone.

**Run the app:**

```bash
# Terminal 1 — Flightdeck + hot reload watcher
uv run kivy-reloader run

# Terminal 2 — trigger a reload (or just save a watched file)
uv run python main.py
```

Both `uv run kivy-reloader run` and `uv run python main.py` work. If the phone app isn't running and the desktop tries to reach it, the connection times out — that's normal behavior, not an error.

---

## Contribution

Have ideas or found a bug? Please open an **[issue](https://github.com/kivy-school/kivy-reloader/issues)** or a **[pull request](https://github.com/kivy-school/kivy-reloader/pulls)**.

## Need help?

Come say hi in the **[Kivy Discord](https://chat.kivy.org/)** support channels — we're happy to help!

<!-- link notes -->

[Kaki]: https://github.com/tito/kaki
