-
Notifications
You must be signed in to change notification settings - Fork 0
Troubleshooting
Run paf doctor first — it diagnoses the most common build-environment
problems.
Gradle 8.4 + AGP 8.2 need JDK 17–21. JDK 22+ can't even run Gradle 8.4. If
your default java is newer (e.g. JDK 25), ENPAF tries to auto-detect a usable
JDK 17 and pin JAVA_HOME for the build — but the reliable fix is to install
JDK 17 and point JAVA_HOME at it:
setx JAVA_HOME "C:\Program Files\Eclipse Adoptium\jdk-17.0.x-hotspot"Open a new terminal and re-run the build.
Install Android Studio (bundles the SDK) or set ANDROID_HOME:
setx ANDROID_HOME "%LOCALAPPDATA%\Android\Sdk"OneDrive's "Files On-Demand" keeps file handles / read-only placeholders, which
breaks Gradle's own delete steps. ENPAF works around this by relocating the
build outside OneDrive to %LOCALAPPDATA%\enpaf\builds\<name>-<hash>. If you
still hit locks:
-
Pause OneDrive sync during builds, or
-
Set
ENPAF_BUILD_DIRto a path outside any synced folder:$env:ENPAF_BUILD_DIR = "D:\enpaf-builds"
Same root cause (OneDrive read-only placeholders). ENPAF clears read-only bits before overwriting; if it persists, pause OneDrive or build from a non-synced folder.
The first build downloads the Gradle distribution and Android dependencies and Chaquopy assembles the Python runtime. Let it finish once; later builds reuse the cache.
A bundled Python module imported a third-party library at module top level.
Chaquopy only ships the stdlib + your python_requirements. Fixes:
- Move the import inside the function that uses it (lazy import).
- Or add the package to
enpaf.jsonpython_requirementsso Chaquopy bundles it.
(That's exactly why the framework imports Jinja2 lazily — see Architecture → Runtime constraints.)
The app's source files are packaged read-only. Don't write next to them — use
Storage (which writes to ENPAF_DATA_DIR) or read ENPAF_DATA_DIR yourself.
See Storage.
An already-installed APK keeps the old code. Rebuild and reinstall:
paf build apk && adb install -r dist/<name>-<version>.apkIf installing a new build silently fails (or the device clearly keeps the old
one), check the version. The builder derives versionCode from enpaf.json
version:
versionCode = major*10000 + minor*100 + patch
Rebuilding the same version (e.g. 1.0.3 twice) produces the same
versionCode, and Android refuses to install an update with an equal (or lower)
versionCode over an existing app. Fix: bump version in enpaf.json before
rebuilding an update — e.g. 1.0.3 → 1.0.4. If you must keep the version, fully
uninstall the old app first (adb uninstall <package>).
If a freshly built APK still crashes, capture logs instead of guessing:
adb logcat | findstr /R "AndroidRuntime python.stderr chaquopy"(grep -E on macOS/Linux.) The Python traceback usually appears under
python.stderr.
Use from android.provider import Settings, not
import android.provider.Settings as Settings. The aliased form runs a bare
import android first, which Chaquopy can't resolve.
You probably emitted with app.events.emit(...) (Python-only) instead of
app.emit(...) (Python and JS). Use app.emit for anything the UI must
receive. See Events.
Dangerous permissions need a runtime request, not just an enpaf.json entry:
await enpaf.permissions.request(["CAMERA"]);Confirm the permission is also declared in enpaf.json permissions.
For a WebView camera (e.g. a QR scanner) you need all of:
- The runtime
CAMERApermission (await enpaf.permissions.request(["CAMERA"])). - The WebView to grant
onPermissionRequestand setsetMediaPlaybackRequiresUserGesture(false)so the preview<video>autoplays — the framework's generatedMainActivitydoes both (rebuild with a current framework). - The camera JS library bundled locally, not loaded from a CDN — the dev
LAN often has no internet, so a CDN
<script>never loads and the scanner can't start.
An unsigned release APK can't be installed. ENPAF signs release builds
automatically; if you supplied a custom signing block or --keystore, verify
the keystore path and passwords. See Release & Signing.
The JS bridge uses Socket.IO with an HTTP fallback (/enpaf-api/bridge-call), so
calls still work. If you need WebSocket specifically, ensure flask-socketio and
simple-websocket are installed and no proxy is stripping the upgrade.
paf run --port 3000Open an issue at https://github.com/aaalllexxx/enpaf/issues with paf doctor
output and (for on-device crashes) the relevant adb logcat lines.
Getting started
Reference
- CLI Reference
- enpaf.json Configuration
- Python API
- JavaScript Bridge
- Storage
- Events
- Device Capabilities
Building & shipping
Project