eb8e66e427
Document how to build, package and release the player so the knowledge is not rediscovered on each machine or session. New file: .github/instructions/kiwy-build-and-development.instructions.md Contents: - Entry points: src/main.py on Linux/Pi, windows/run_win.py on Windows (which patches platform differences before running main.py). - Verified toolchain: Python 3.12.9 x64 in windows\venv, Kivy 2.3.1, PyInstaller 6.21.0. Python 3.13+/3.14 is unsupported for the Windows build because Kivy 2.3.1 has no wheels for them. - Build commands (pyinstaller build.spec, build_win.bat) and the real output path, including the note that cefpython3 is not installed in this venv, so the embedded-CEF engine is inactive and web links use the subprocess adapter. - build.spec expectations: runtime hook for DPI awareness, console=True, excludes, and the rule that lazily/dynamically imported modules must be listed in hiddenimports or the packaged exe fails with ModuleNotFoundError. - Code signing constraint: production hosts enforce Smart App Control, where an unsigned (or self-signed) exe is blocked at kernel level, so a public CA cert is required. - Verification: py_compile gate, the need to close the running player before a rebuild (output lock / "Access is denied"), the .exe reserved-device-name pitfall that makes Test-Path report a false positive without -LiteralPath, and the stale duplicate one-file exe at windows\dist\KiwySignagePlayer.exe that must not be deployed. - Release checklist and commit hygiene (do not track dist/build output or the player_auth.json credential files).
141 lines
6.3 KiB
Markdown
141 lines
6.3 KiB
Markdown
---
|
|
description: "Use when building, compiling, packaging or releasing the Kiwy Signage Player: PyInstaller build, .exe generation, build.spec, hiddenimports, code signing, Smart App Control, Windows development, Raspberry Pi deployment, or adding new modules under src/. Covers the exact build commands, environment constraints, bundling rules and verification steps."
|
|
name: "Kiwy Build & Development"
|
|
---
|
|
|
|
# Kiwy Signage Player — Build & Development
|
|
|
|
Cross-platform Kivy digital signage player.
|
|
|
|
- **Raspberry Pi / Linux** — `src/main.py` is the entry point (root `install.sh`, `start.sh`).
|
|
- **Windows** — `windows/run_win.py` is the entry point; it sets Windows env vars, imports
|
|
`main.py`, then monkey-patches platform differences. Packaged to `.exe` with PyInstaller.
|
|
|
|
## Ground Rules
|
|
|
|
- **Keep `src/main.py` cross-platform.** Windows-specific behaviour belongs in
|
|
`windows/run_win.py` (see `_patch_main()`), Pi-specific behaviour in `main.py` guarded
|
|
by capability checks. Do not add Windows-only imports to `main.py`.
|
|
- **Rebuild is mandatory.** The `.exe` bundles `src/`, so Python edits are invisible until
|
|
you rebuild. There is no hot reload in the packaged app.
|
|
- **`dist/` is a runtime folder, not just build output.** It holds `config/`, `media/`,
|
|
`playlists/`, `logs/`, `.kiosk-profile/` and `.player_heartbeat`. Never wipe `dist/`
|
|
blindly; a `--clean` rebuild preserves it, but a manual delete destroys player state.
|
|
|
|
## Environment
|
|
|
|
| Item | Value |
|
|
|------|-------|
|
|
| Interpreter | **Python 3.12.9** (64-bit) — project venv at `windows\venv` |
|
|
| Kivy | 2.3.1 |
|
|
| PyInstaller | 6.21.0 |
|
|
| Linux target | Python 3.13 (`repo/python-wheels/`, `repo/system-packages/`) |
|
|
|
|
- **Python 3.13+/3.14 is NOT supported for the Windows build** — Kivy 2.3.1 has no wheels
|
|
for them.
|
|
- `cefpython3` is **not installed** in the project venv. The embedded-CEF web-link engine is
|
|
therefore unavailable and web links fall back to the Chrome/Edge subprocess adapter.
|
|
Installing `cefpython3` (uncomment it in `windows/requirements_win.txt`) restores the
|
|
CEF engine.
|
|
|
|
## Build
|
|
|
|
From `windows\`:
|
|
|
|
```
|
|
venv\Scripts\python.exe -m PyInstaller build.spec --clean --noconfirm
|
|
```
|
|
|
|
Or the full one-click path (creates venv, installs deps, builds, then signs):
|
|
|
|
```
|
|
build_win.bat
|
|
```
|
|
|
|
Output (folder mode, via `COLLECT`):
|
|
|
|
```
|
|
windows\dist\KiwySignagePlayer\KiwySignagePlayer.exe <- the real build output
|
|
```
|
|
|
|
**Deployment hazard:** `windows\dist\KiwySignagePlayer.exe` (one level up) is a stale
|
|
leftover from an older single-file build of the same name. It is not refreshed by the
|
|
current spec, so deploying it ships old code. Always take the executable from the
|
|
`KiwySignagePlayer\` subfolder, and delete the stray copy if it reappears.
|
|
|
|
### `build.spec` facts
|
|
|
|
- Entry point `run_win.py`; `pathex=[BUILD_DIR, SRC_DIR]` so `src/` modules resolve.
|
|
- `runtime_hooks=[pyi_runtime_hook.py]` — sets per-monitor DPI awareness **before** SDL/Kivy
|
|
initialise. Keep DPI work here; it must run before any window is created.
|
|
- `datas += Tree(src)` bundles all of `src/`. `console=True` so startup errors and the Kivy
|
|
log remain visible — do not flip this to `False` without a reason.
|
|
- `hiddenimports` must list modules that PyInstaller's static analysis **cannot** see:
|
|
lazily imported ones (`cef_browser` is imported inside a function) or dynamic imports
|
|
(`getattr`, `importlib`). Top-level imports such as `weblink_session` are found
|
|
automatically via `pathex`, but listing them is harmless insurance.
|
|
**When you add a module under `src/` that is imported lazily or by string, add it to
|
|
`hiddenimports` or the packaged exe will fail at runtime with `ModuleNotFoundError`.**
|
|
- `excluded_imports` drops Linux-only packages (`evdev`, `gi`, GStreamer) and the
|
|
non-matching `cefpython3` `.pyd` variants.
|
|
|
|
## Code Signing (production constraint)
|
|
|
|
Production PCs run with **Smart App Control enforced** (`VerifiedAndReputablePolicyState=1`,
|
|
UMCI enforced) with **no "Run anyway" bypass** — an unsigned exe is blocked at kernel level.
|
|
|
|
- A **self-signed certificate does NOT satisfy Smart App Control.** A cert from a reputable
|
|
public CA is required. `create_self_signed_cert.ps1` is dev-only.
|
|
- Provide a cert as `KIWY_SIGN_PFX` (+ optional `KIWY_SIGN_PFX_PASSWORD`) or drop
|
|
`kiwy_signing.pfx` in `windows\`; `build_win.bat` then signs via `sign_exe.ps1`
|
|
(signtool with RFC3161 timestamp when available).
|
|
- See `documentation/CODE_SIGNING_SMART_APP_CONTROL.md`.
|
|
|
|
## Verify Before Committing
|
|
|
|
Fast syntax gate (no build, seconds):
|
|
|
|
```
|
|
python -m py_compile src/main.py src/weblink_session.py windows/run_win.py
|
|
```
|
|
|
|
**Close the running player before rebuilding.** A running
|
|
`dist\KiwySignagePlayer\KiwySignagePlayer.exe` locks the output and the build fails with
|
|
"Access is denied". Chrome/Edge kiosk processes left over from web-link playback can also
|
|
hold locks; if the build fails, check for stray `msedge.exe` / `chrome.exe` before retrying.
|
|
|
|
Because `.exe` is a **reserved Windows device name** as well as a real file, use
|
|
`Test-Path -LiteralPath` when probing for the executable, otherwise the path silently
|
|
resolves to the console device.
|
|
|
|
Development run — **use this on a SAC-locked host**, since the unsigned exe cannot launch:
|
|
|
|
```
|
|
cd windows
|
|
venv\Scripts\activate
|
|
python run_win.py
|
|
```
|
|
|
|
Diagnose playback transitions via the trace log (`logs\playback_trace.log`), written by
|
|
`src/playback_trace.py`.
|
|
|
|
## Release Checklist
|
|
|
|
1. Bump `PLAYER_VERSION` in `src/main.py` **and** `filevers`/`prodvers`/`FileVersion`/
|
|
`ProductVersion` in `windows\version_info.txt`; keep them in sync.
|
|
2. Rebuild (`build_win.bat`).
|
|
3. Confirm the exe is signed (`Get-AuthenticodeSignature`); unsigned builds are blocked on
|
|
production hosts.
|
|
4. Smoke-test a mixed playlist: image → video → weblink → image, verifying durations, audio
|
|
(`audio: off` / `muted`), and a clean exit/restart.
|
|
|
|
## Commit Hygiene
|
|
|
|
- Never commit `windows\build\` or `windows\dist\` (git-ignored). Tracked build output such
|
|
as `windows\archive_list.txt` and `windows\build_last.txt` is the exception, not the rule.
|
|
- **Do not commit `player_auth.json` or `src/player_auth.json`** — they contain live
|
|
credentials (`auth_code`, `player_id`, `server_url`). These are currently tracked; treat any
|
|
future change to them as a deliberate, reviewed decision.
|
|
- Do not commit `config\app_config.json` values that are host-specific without checking
|
|
whether they belong in the repo default.
|