Skip to content
Back to skills

Course To Apk

ASecurity

Package an existing interactive course generated by the book-to-course skill (a folder with index.html, assets/ and course/data.js, or its .zip) into a signed Android APK — a light offline WebView app to install on a phone or tablet. Checks the build tools on the machine (JDK, Android SDK build-tools and platform), tells the user exactly what is missing and where to get it, and can download it for them. Use this whenever the user wants a course "na telefon/tablet", "na Androida", "jako aplika...

  • 47 stars
  • 0 votes
  • 0 copies
  • 0 views
  • Added October 5, 2026
ai-agentspythongojavashellbashdebugging

Security analysis

A100/100

Pro scans all 14 files and shows the line behind each finding

Scanned October 5, 2026

npx -y skills add sebastianhaba/book-to-course-skill --skill course-to-apk --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Course To Apk?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Course To Apk
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/sebastianhaba-course-to-apk/badge)](https://www.skillsdirectory.com/skills/sebastianhaba-course-to-apk)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: course-to-apk
description: Package an existing interactive course generated by the book-to-course skill (a folder with index.html, assets/ and course/data.js, or its .zip) into a signed Android APK — a light offline WebView app to install on a phone or tablet. Checks the build tools on the machine (JDK, Android SDK build-tools and platform), tells the user exactly what is missing and where to get it, and can download it for them. Use this whenever the user wants a course "na telefon/tablet", "na Androida", "jako aplikację", "zrób z kursu APK", "course to apk", wants to learn from their generated course on a mobile device offline, or wants to rebuild/update a course app after adding chapters — even if they don't say "APK" explicitly. Do NOT use for building a course from a book (that is book-to-course), for iOS apps, or for general Android app development.
---

# Course → Android APK

Wraps a finished book-to-course course into a small Android app: one Activity with a WebView that serves the course
files from inside the APK. No Gradle, no Android Studio project, no network permission — the build calls the SDK tools
directly (`aapt2 → javac → d8 → zipalign → apksigner`), so the APK is roughly the size of the course plus ~10 KB.

The app wrapper (`assets/android/`) and the scripts are fixed and tested — **your job is the conversation around them**:
find the course, get the toolchain in place with the user's consent, build, and explain how to put it on the device.

| script (in `scripts/`) | purpose |
|---|---|
| `toolchain.py [--json]` | what is installed, what is missing, where to download it; exit 0 = ready |
| `setup_toolchain.py --dry-run` | list exactly what would be downloaded (name, size, URL) — downloads nothing |
| `setup_toolchain.py --show-license` | print the Android SDK licence text |
| `setup_toolchain.py --accept-licenses` | download only the missing parts into `~/.local/share/course-to-apk` (no sudo) |
| `build_apk.py COURSE_DIR [--install]` | build the signed APK into `<COURSE_DIR>-android/` |

All scripts are Python 3 standard library only.

## Workflow

### 1. Find the course
A course folder has `index.html`, `assets/app.js` and `course/data.js`. Look where the user points, in the current
directory, or among recent book-to-course output. If they give a `.zip` (from `pack_course.py`), unzip it next to the zip
first — it contains one top folder named after the course; that folder is COURSE_DIR. If `content/` exists but `course/data.js` is missing or older than the lessons, the course was not rebuilt —
run book-to-course's `build_course.py COURSE_DIR` first (when that skill is available), otherwise ask the user to.

### 2. Check the toolchain
```bash
python3 scripts/toolchain.py
```
It searches well beyond PATH (JAVA_HOME, ANDROID_HOME, `~/Android/Sdk`, `~/.jdks`, Android Studio's bundled JBR,
`/usr/lib/jvm`, …), so a JDK that `which java` does not see is still found. If it prints **READY**, go to step 4.

### 3. Something is missing → ask, don't assume
Tell the user, in their language, what is missing — use the report's lines, they already contain the official download
links and package-manager commands for their OS. Then run `setup_toolchain.py --dry-run` so you can quote the real sizes
and URLs, and ask them to choose (AskUserQuestion works well here):

- **"I'll install it myself"** — give the list again as a short checklist (what, where from, and that a non-standard
  location needs `JAVA_HOME` / `ANDROID_HOME`). Then **stop and wait**. Do not poll, do not build, do not download
  anything. When they write that it's installed, rerun `toolchain.py`; if something is still missing, say exactly what
  and wait again.
- **"Download it for me"** — the Android SDK packages are under the Android SDK License Agreement
  (https://developer.android.com/studio/terms; full text via `--show-license`). Their choice of this option must include
  agreeing to it — say so in the question. Only then run
  `python3 scripts/setup_toolchain.py --accept-licenses` (≈320 MB if the JDK is also missing, ≈125 MB otherwise; it
  verifies checksums and installs only into `~/.local/share/course-to-apk`, nothing system-wide, no sudo).

Why the care: downloading hundreds of megabytes and accepting a licence are the user's decisions, not yours, and a user
who said they'd install things themselves is mid-installation — building or downloading behind their back collides with that.

### 4. Build
```bash
python3 scripts/build_apk.py "<COURSE_DIR>"
```
Defaults that are right for almost everyone — mention them, don't ask:
- **Output** `<COURSE_DIR>-android/<course-id>.apk`, next to the course folder; `apk.json` there remembers the package id,
  label, icon colour and an auto-incremented versionCode.
- **Signing** with the Android debug key `~/.android/debug.keystore` (the standard developer certificate; created with
  keytool if it doesn't exist). Fine for installing on your own devices; it is not a Play Store release key. If the user
  has their own keystore: `--keystore FILE --key-alias A --ks-pass P` (or `APK_KS_PASS` env var so the password doesn't
  land in shell history); it's remembered in `apk.json`.
- **Package id** `net.booktocourse.<course_id>`, **label** = course title. Override with `--package` / `--label` only
  when asked — changing the package later makes Android treat it as a different app and the learner loses progress.
- **Android 7.0+** (minSdk 24); targetSdk = the newest platform installed.

If the build fails, the error names the tool and shows its output; see `references/troubleshooting.md`.

### 5. Hand it over
Tell the user in a few lines: where the APK is (absolute path), its size, and how to install it:
- **Copy to the device** (USB cable, cloud drive, e-mail to yourself), open the file on the device, allow
  "install unknown apps" for the app that opens it when Android asks; Play Protect may warn about an unknown developer → "Install anyway".
- **Or over USB with adb**: enable Developer options → USB debugging, connect, then `build_apk.py … --install`
  (or `adb install -r <apk>`). Offer this if `toolchain.py` showed adb and a device is connected (`adb devices`).

Also say, briefly:
- Progress is stored inside the app on the device (not in `progress/progress.json` of the computer copy) and survives
  updates — **rebuild with the same folder and key** after adding chapters and install over the old app. Uninstalling deletes it.
- Code exercises: the "Run tests" button needs the computer version (`start.sh`/`start.bat`); on the phone the page
  shows the test command instead. Lessons, quizzes, tests and flashcards all work offline.

## What the app does (so you can answer questions)
- Serves the course from `https://appassets.androidplatform.net/` via `shouldInterceptRequest` — a reserved host that
  never hits the network, giving the page a stable origin for `localStorage`. No INTERNET permission; links to other
  sites open in the user's browser.
- Back button/gesture goes back through the course's history, then closes the app; edge-to-edge insets (status bar,
  cutouts, keyboard) are handled; dark/light follows the system on first launch, then the course's own theme toggle.
- `alert()`/`confirm()` show real dialogs (the player avoids them anyway).

To change the wrapper itself (e.g. lock orientation), edit `assets/android/` — `MainActivity.java`, `AndroidManifest.xml`
(placeholders `{{PACKAGE}}`, `{{LABEL}}`), `res/`. Keep it framework-only: there is no Gradle, so AndroidX libraries can't be added.

Files in this skill

  • SKILL.md7.4 KB
  • assets/android/AndroidManifest.xml1 KB
  • assets/android/res/drawable/ic_book.xml510 B
  • assets/android/res/mipmap-anydpi-v26/ic_launcher.xml296 B
  • assets/android/res/mipmap/ic_launcher.xml305 B
  • assets/android/res/values-night/colors.xml108 B
  • assets/android/res/values-night/themes.xml347 B
  • assets/android/res/values/colors.xml152 B
  • assets/android/res/values/themes.xml442 B
  • assets/android/src/net/booktocourse/app/MainActivity.java7.9 KB
  • references/troubleshooting.md2.8 KB
  • scripts/build_apk.py13.9 KB
  • scripts/setup_toolchain.py10.9 KB
  • scripts/toolchain.py13.4 KB

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…