sercrod

Extra A - Package as an app

The main tutorial finished a Todo app as normal HTML. This extra keeps that Sercrod logic unchanged, prepares the web files for Capacitor, and shows the path to an Android debug APK.

This is not a Capacitor tutorial. The goal is to make the Sercrod side clean: one app entry, local assets, and no hidden dependency on the public documentation site.

This extra shows how to create an Android APK that contains the finished Sercrod Todo app. The same prepared Sercrod files can also be used as the app contents for an iOS IPA. However, IPA creation depends more on each developer's environment, so we do not cover it here.

Target shape

Capacitor expects a directory of web files. Put the finished Todo page and the files it needs into one app-focused directory.

todo-app/
	index.html
	sercrod.js
	adapters/
		capacitor/
			filesystem.js
	assets/
		style.css
		icons...

The wrapper reads this directory as its web app. Sercrod still owns the Todo behavior inside index.html.

Prepare the page

Example app index

For the app package, create an index.html inside the prepared app directory. Notice that sercrod.js is loaded with a relative path.

<!doctype html>
<html lang="en">
<head>
	<meta charset="utf-8">
	<meta name="viewport" content="width=device-width, initial-scale=1">
	<title>Sercrod Todo</title>
</head>
<body>
	<script src="./sercrod.js"></script>
	<script src="./adapters/capacitor/filesystem.js"></script>

	<serc-rod data='{"draft":"","todos":[{"title":"Buy milk","done":false},{"title":"Pay bills","done":true}]}'>
		<h2>Todo</h2>
		<p *if="todos.length === 0">No todos yet.</p>
		<ul *else>
			<li *for="todo of todos">
				<span *if="todo.done">[x]</span>
				<span *else>[ ]</span>
				<span>%todo.title%</span>
				<button type="button" @click="todo.done = !todo.done">
					Toggle
				</button>
			</li>
		</ul>
		<p><label>Title: <input type="text" *input="draft" *lazy></label></p>
		<p *if="draft">Draft: %draft%</p>
		<p *else>Type a Todo title.</p>
		<button type="button" @click="if(draft.trim()){ todos.push({ title: draft, done: false }); draft = '' }">
			Add
		</button>
		<button type="button" *save.file>Save</button>
		<button type="button" *load.file>Load</button>
	</serc-rod>
</body>
</html>

Use app paths

A documentation page can depend on site paths such as /assets/style.css or /sercrod.js. An app package should be more self-contained.

<link rel="stylesheet" href="./assets/style.css">
<script src="./sercrod.js"></script>
<script src="./adapters/capacitor/filesystem.js"></script>

File directives in Capacitor

In a normal browser, *save.file and *load.file can use the browser's download and file selection features.

Inside a Capacitor Android app, however, a WebView does not handle device storage in exactly the same way as a regular browser. In particular, writing data to the device is usually better routed through Capacitor's own APIs.

For that reason, when a Capacitor app uses file-related directives such as *save.file or *load.file, load dist/adapters/capacitor/filesystem.js in addition to dist/sercrod.js.

The HTML does not change. The adapter connects the same Sercrod directives to Capacitor's file handling.

For browser-local JSON persistence that does not need device file pickers, use *save.store="'key'" and *load.store="'key'". Those store forms use IndexedDB in the WebView and do not use the Capacitor filesystem adapter.

When debugging an app build, check the adapter from the WebView console:

window.__Sercrod.adapter_map.file
window.SercrodCapacitorFilesystemAdapter.diagnose()
localStorage.getItem("sercrod-capacitor-filesystem:last-file")
localStorage.getItem("sercrod-capacitor-filesystem:last-status")

The file role should be capacitor.filesystem, and has_filesystem, has_write_file, and has_read_file should be true. The last-file record shows the directory and file name Sercrod will try to load next. The last-status record shows whether save or load succeeded, which directories were tried, and any plugin error messages. If the adapter script loads but the Filesystem plugin is missing, install and sync @capacitor/filesystem in the Capacitor project.

On a phone, the adapter also writes a small status line after the Save or Load button. After tapping Save, you should see a message such as Saved: DATA/Sercrod-20260515-213000.json, or a concrete Save failed message.

Capacitor config

In a Capacitor project, point webDir at the directory that contains the prepared Sercrod app.

import type { CapacitorConfig } from '@capacitor/cli';

const config: CapacitorConfig = {
	appId: 'com.example.sercrodtodo',
	appName: 'Sercrod Todo',
	webDir: 'todo-app'
};

export default config;

The important Sercrod-side value is webDir. It should point to the directory that contains index.html, sercrod.js, and the local assets.

Android handoff

After the Sercrod app directory works as a normal web app, initialize Capacitor, add Android, and sync the web files into the native project.

npm i @capacitor/core
	npm i -D @capacitor/cli
	npx cap init
	npm i @capacitor/android
	npm i @capacitor/filesystem
	npx cap add android
npx cap sync android
npx cap open android

From there, Android Studio can build the app. A development APK is usually created from the Android project with a debug build.

cd android
./gradlew assembleDebug

On Windows, use the Gradle wrapper batch file instead.

cd android
gradlew.bat assembleDebug

The debug APK is commonly written here:

android/app/build/outputs/apk/debug/app-debug.apk

This APK is enough to prove the handoff: the finished Sercrod Todo app has been packaged as an Android app. Release builds, app store release, and other native plugins are separate Android and Capacitor work.

iOS handoff on macOS

The same prepared web files can be used for an iOS wrapper on macOS. The web app stays the same; only the native shell changes.

npm i @capacitor/ios
npx cap add ios
npx cap sync ios
npx cap open ios

Capacitor's iOS target uses Xcode for native builds. The important Sercrod side detail is still the same webDir and the same prepared HTML, script, and adapter files.

Capacitor reference

Use the official Capacitor guide for setup details and current platform requirements.

Next

This extra prepares the handoff and reaches an Android debug APK. The Todo app remains a Sercrod web app; the wrapper packages it.

Previous: Save and load

Back to Tutorial index