From 4e0f4ed7b5f8e844c48afbb0aa11631e5895b65a Mon Sep 17 00:00:00 2001 From: rdlabo Date: Thu, 22 Oct 2026 17:03:36 +0900 Subject: [PATCH] docs: guide Workers developers from web apps to mobile --- README.md | 104 +++++++++++++++++++++++++++----------------- demo/README.md | 32 +++++++++----- docs/README.md | 51 ++++++++++++++-------- docs/integration.md | 49 +++++++++++++++------ 4 files changed, 153 insertions(+), 83 deletions(-) diff --git a/README.md b/README.md index 870047e..53f8c1a 100644 --- a/README.md +++ b/README.md @@ -4,25 +4,45 @@ Reach people who prefer the browser and people who look for apps in the store. Offer a mobile app alongside your web app, so your users can choose the platform that works for them. -## Choose how to bring your app to mobile +## Your web app can have a mobile version -- **Embed in an existing iOS app** - Add a Workers-powered screen to your UIKit or SwiftUI app. [iOS guide](docs/native-embedding.md#ios). -- **Embed in an existing Android app** - Add a Workers-powered screen to your existing Android app. [Android guide](docs/native-embedding.md#android). -- **Create a new mobile app** - Use Capacitor to build an iOS and Android app for distribution through the App Store and Google Play. [Capacitor guide](docs/integration.md). +If you have a web app running on Cloudflare Workers, you can add an iOS and Android +app built around its existing pages and backend. For example, a Void app with +D1-backed forms can keep its loaders, actions and database on Workers while the +mobile app displays its pages and bundles its public JavaScript and CSS. -[Documentation](docs/README.md) · [Examples](demo/README.md) +cf-workers-native connects your Workers application to a mobile app built with +Capacitor. Capacitor supplies the iOS and Android projects and access to native +plugins. You add a separate mobile build and test your application's flows; you +keep developing and deploying your web app to Cloudflare. -## Keep building the app you know +**Start here: [Add a mobile version to your existing app](docs/integration.md).** +You do not need an existing native app. The guide takes you from choosing your +Worker entry to running your pages on a simulator or emulator. -- **Reuse your pages and flows.** Bring Worker-rendered HTML, links and forms into a mobile WebView. Keep the application's existing rendering model; an SPA rewrite is not a prerequisite. -- **Give your app a mobile home.** Create an iOS and Android app with Capacitor, or bring your Workers pages into a native app you already have. -- **Keep your backend on Workers.** D1, server secrets and cloud-dependent logic stay on the deployed Worker. The separate mobile build leaves your Cloudflare deployment inputs unchanged. -- **Choose what runs on the device.** Start with the default network execution. Where supported, explicitly select public routes for local execution and bundle client assets with the app. +## See an example close to your app -Local execution has [compatibility limits](docs/compatibility.md). Cloud-backed pages still need a connection; bundling their client assets does not make them offline applications. +| What you have | What to try | What the example demonstrates | +| --------------------------------------- | ------------------------------------------------ | -------------------------------------------------------------------------------------------- | +| HTML pages served by a Worker | [Hono / Express pages](demo/rendering/README.md) | Page navigation, forms and redirects inside a mobile app. | +| A Void React Pages app using D1 | [Void + D1 sample](demo/void/README.md) | Server-rendered pages, React interaction and a form that writes to D1. | +| A Next.js app deployed through OpenNext | [OpenNext sample](demo/opennext/README.md) | Connecting generated pages and assets to a mobile build; see its version and feature limits. | + +These are examples and test fixtures, not customer deployment stories. Each guide +states what has been verified. Start with the flow closest to yours, then try it +with your own app. + +## What stays, what you add + +- **Keep your pages and backend.** Reuse supported HTML, links, forms and client interactions. D1, server secrets and cloud-dependent logic stay on Workers. +- **Add a mobile build.** Connect your Worker and public assets to a Capacitor app with its own name and application ID. +- **Check the mobile experience.** Verify login, navigation, data changes, reopening and connection recovery in your application. +- **Prepare for distribution.** Configure signing and store information through the native application workflow. Store submission and review remain separate steps. + +Start with requests running on your existing deployed Worker. Cloud-backed pages +need a connection. Bundled client assets do not make them offline applications. +Optional local execution is covered by the [execution guide](docs/cloudflare-bindings.md#choosing-execution) +and [compatibility limits](docs/compatibility.md). ## Start from your framework @@ -35,47 +55,51 @@ Local execution has [compatibility limits](docs/compatibility.md). Cloud-backed Each guide describes its tested versions and boundaries. Already have a separate frontend calling Worker APIs? Keep that frontend and use the [Fetch-only integration](docs/runtime.md#fetch-only-integration). -## Get your app onto your phone +## Try it with your app -Install the shared JavaScript package in your web project: +You need the application's source, its Worker build and a test Worker URL for +cloud-backed flows. Running iOS requires macOS and Xcode; Android requires the +Android development tools. The [setup guide](docs/integration.md#before-you-start) +links the platform prerequisites. -The `latest` npm tag includes 0.x Preview releases. Install this release explicitly: +Install the package in your web project, then follow the +[complete mobile setup](docs/integration.md#workflow): ```sh npm install --save-exact cf-workers-native@0.1.3 ``` -The mobile entry selects the host. For example, an iOS web entry starts with: - -```ts -import { workersIOS } from "cf-workers-native/ios"; - -const app = workersIOS({ - baseURL: "https://your-worker.example.com/", - render: "/", -}); -await app.ready; -``` - -Use `workersAndroid` from `cf-workers-native/android` or `workersCapacitor` from `cf-workers-native/capacitor` for the other hosts. All three share the same runtime options and [Vite/esbuild tooling](docs/build-setup.md). - -This entry is one part of the setup: connect the existing Worker to a **separate mobile build**, then package its output with your chosen native host. The [embedding guide](docs/native-embedding.md) and [Capacitor guide](docs/integration.md) cover the complete path. For an existing native app, build the web assets in the web project or CI; the native project does not need Capacitor CLI commands or configuration. +Installation alone does not generate a mobile project. The guide covers adding +Capacitor, configuring the mobile build, and running it on iOS or Android. Your +first milestone is one existing page, a link to another page, and a working form +or data action on a simulator or emulator. -**All 0.x releases are Preview releases.** APIs may change. Android embedding requires WebView `MULTI_PROFILE` support. The native Android SDK is available from Maven Central at version `0.1.2`. Read the [native requirements](docs/native-embedding.md#dependency-setup) before integrating. Upgrading from `workers-capacitor`? Follow the [migration steps](docs/integration.md#migrating-from-the-old-npm-package). +**All 0.x releases are Preview releases**, including those on npm's `latest` tag. +APIs may change. Use your app's actual flows to evaluate the fit before distribution. +Upgrading from `workers-capacitor`? Follow the [migration steps](docs/integration.md#migrating-from-the-old-npm-package). ## Build with your AI assistant -Open your application repository and give your assistant this prompt, replacing the target with **iOS**, **Android** or **Capacitor**: +Open your application repository and give your assistant this prompt: ```text -Read https://github.com/rdlabo-dev/cf-workers-native/blob/main/README.md -and the integration guide for our target: . -Bring this Workers application to that target using cf-workers-native@0.1.3. -Preserve its pages, routes, authentication and Cloudflare deployment configuration. -For an existing native app, preserve its entry point and navigation. -Verify the actual user flows on the target platform and report remaining limits. +Read https://github.com/rdlabo-dev/cf-workers-native/blob/main/docs/integration.md. +Add an iOS and Android version of this Workers web app using cf-workers-native@0.1.3 +and Capacitor. Preserve the existing pages, backend and Cloudflare deployment configuration. +Use an existing test Worker for cloud-backed requests; ask before any cloud deployment. +Start by verifying one page, navigation and a form or data action on a simulator/emulator. +Then verify the app's authentication and main user flow, and report remaining limits. ``` +Provide your app name, application ID and test Worker URL if you have them. + +## Already have a native app? + +Embed a Workers-powered screen in your existing [UIKit / SwiftUI app](docs/native-embedding.md#ios) +or [Android app](docs/native-embedding.md#android). These integrations use the +native SDKs and a shared web build. Follow the [dependency setup](docs/native-embedding.md#dependency-setup) +for the matching npm, SwiftPM and Maven versions and Android WebView requirements. + ## Make it ready for your users Follow a real flow from launch to sign-out: load a page, navigate, submit a form, reopen the app and check what happens when the network is unavailable. Keep secrets on the Worker and enforce authentication and authorization there. The [integration checklist](docs/integration.md#6-verify-the-existing-application-in-capacitor) and [native embedding checks](docs/native-embedding.md#verification) explain what to verify. diff --git a/demo/README.md b/demo/README.md index bc04129..bba4611 100644 --- a/demo/README.md +++ b/demo/README.md @@ -1,17 +1,25 @@ # cf-workers-native examples -Choose the example closest to the experience you want to build: - -| Experience | Example | -| --------------------------------------------------- | ------------------------------------------------------------------------ | -| A Workers screen in an existing iOS app | [UIKit and SwiftUI consumer](tests/native-embedding/ios/README.md) | -| A Workers screen in an existing Android app | [Independent Android consumer](tests/native-embedding/android/README.md) | -| Worker-rendered pages, links and forms in Capacitor | [Hono and Express document rendering](rendering/README.md) | -| React pages with D1-backed forms | [Void sample](void/README.md) | -| Next.js pages through OpenNext | [OpenNext sample](opennext/README.md) | -| An existing frontend calling a Worker | The Fetch-only demo below | - -The native consumers are executable acceptance fixtures; use the [embedding guide](../docs/native-embedding.md) for application integration. Framework samples describe their own execution and verification boundaries. +Start with an example that resembles your existing Cloudflare Workers app, then +use the [integration guide](../docs/integration.md) to add a mobile version of your +own application. + +| Your app | Example | What to look for | +| ------------------------------------ | --------------------------------------- | ------------------------------------------------------------------------ | +| Worker-rendered pages and forms | [Hono and Express](rendering/README.md) | Follow a link, submit a form and navigate after a redirect. | +| Void React Pages with D1 | [Void sample](void/README.md) | Render a page, interact with React, and persist a form submission in D1. | +| Next.js deployed through OpenNext | [OpenNext sample](opennext/README.md) | Connect generated pages and assets; check the sample's supported flows. | +| A separate frontend calling a Worker | The Fetch-only demo below | Keep the frontend and connect its requests. | + +These are repository examples and test fixtures. Read each sample's setup and +verification boundaries; there is no shared one-command launcher for all samples. +For your first mobile run, choose a page and one action you can verify on both the +web and mobile app. Authentication and distribution need checks in your own app. + +Already maintain a native app? The [UIKit / SwiftUI consumer](tests/native-embedding/ios/README.md) +and [Android consumer](tests/native-embedding/android/README.md) are executable +acceptance fixtures for embedding. Use the [embedding guide](../docs/native-embedding.md) +for application integration. The rest of this page runs a minimal Workers Fetch Handler inside Capacitor. It illustrates Fetch-only integration; use the rendering example above for full document navigation. diff --git a/docs/README.md b/docs/README.md index 7258d71..09bf2a7 100644 --- a/docs/README.md +++ b/docs/README.md @@ -1,28 +1,45 @@ -# Bring your Workers app to mobile +# Add a mobile version to your Cloudflare Workers app -Bring the app you built with Workers or Void to people who use the web and people who find apps in the store. Start with the integration that fits your app, then connect its existing Workers build. +Keep your web application on Cloudflare and bring its pages and flows to iOS and +Android. Start by running a small part of your existing app on a simulator or +emulator, then verify the rest of the experience before distribution. -## Choose your mobile host +## Start with something you recognize -| Target | Guide | What to expect | -| ------------- | ------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------ | -| **iOS** | [Embed in UIKit or SwiftUI](native-embedding.md#ios) | Add the `WorkersIOS` Swift package product and a bundled web build to your existing app. | -| **Android** | [Embed in an existing app](native-embedding.md#android) | Build the Android SDK artifact locally and open its dedicated screen from an Activity. Requires WebView `MULTI_PROFILE`. | -| **Capacitor** | [Build a mobile app](integration.md) | Use a Capacitor app shell and general native plugins, starting from your existing Worker. | +| Your starting point | See it in an example | Connect your own app | +| ------------------------------------- | --------------------------------------------------- | ----------------------------------------------------------- | +| Worker-rendered HTML and forms | [Hono / Express pages](../demo/rendering/README.md) | [Worker build setup](build-setup.md#frameworks) | +| Void React Pages with D1 | [Void sample](../demo/void/README.md) | [Void integration](void.md) | +| Next.js on Workers through OpenNext | [OpenNext sample](../demo/opennext/README.md) | [OpenNext integration](opennext.md) | +| A separate frontend using Worker APIs | [Fetch-only demo](../demo/README.md) | [Fetch-only integration](runtime.md#fetch-only-integration) | -The [shared web build](native-embedding.md#shared-web-build) connects the iOS and Android hosts to your Worker. The Capacitor guide includes its own build steps. All three use `cf-workers-native@0.1.3`, with a separate mobile build that preserves the Cloudflare deployment inputs. +Samples show specific integrations and their verification boundaries. They do not +establish that every application using the same framework will work unchanged. -## Connect your framework +## Make your first mobile build -Choose the framework's Worker entry and asset setup before building: +Follow [Add a mobile version with Capacitor](integration.md). Capacitor creates the +iOS and Android projects; cf-workers-native connects them to your Workers app. +You do not need an existing native application. -- [Hono](build-setup.md#hono): Fetch handlers and Worker-rendered HTML. -- [Workers Express](build-setup.md#workers-express): Express through the Workers `cloudflare:node` entry. -- [Void React Pages](void.md): generated Worker, React client assets and D1-backed pages. -- [Next.js / OpenNext](opennext.md): generated Worker and client assets, with explicit version and execution limits. -- [Separate frontend](runtime.md#fetch-only-integration): keep your UI and connect its existing API requests. +1. Identify your Worker build, public assets and test Worker URL. +2. Add the mobile project and its separate build configuration. +3. Run one existing page, follow a link, and submit a form or perform a data action. +4. Verify login, data changes, reopening and network recovery in your own app. +5. Prepare signing and distribution using the native app's release workflow. -Use [Vite or esbuild](build-setup.md#tools) for the mobile build. Framework support is scoped to each guide's verified paths; [compatibility](compatibility.md) records the wider API boundaries. +The guide includes [prerequisites](integration.md#before-you-start) and a +[prompt for your AI assistant](integration.md#prompt-to-give-your-ai-assistant). +Start with the existing Worker handling requests remotely; local execution is an +optional later step. Setup currently requires configuration, not a single project-generation command. + +## Add a screen to an existing native app + +If you already maintain an iOS or Android app, use [native embedding](native-embedding.md) +instead. Follow the [UIKit / SwiftUI](native-embedding.md#ios) or +[Android](native-embedding.md#android) guide and the +[published dependency matrix](native-embedding.md#dependency-setup). Android uses +the Maven SDK and requires WebView `MULTI_PROFILE` support. ## Understand where your code runs diff --git a/docs/integration.md b/docs/integration.md index 2c61c22..5f303eb 100644 --- a/docs/integration.md +++ b/docs/integration.md @@ -10,25 +10,26 @@ Follow the [workflow](#workflow) below yourself, or give the [integration prompt The primary success criterion is a working native application with minimal integration effort, not a new application architecture. Keep ordinary HTML documents, links and forms where the application uses them. SPA conversion, a new client router, App Shell redesign, SSR/API separation and adding hydration are not prerequisites. -## How existing Worker pages reach the screen +## Before you start -With `render`, the library supplies the Worker's response as the response to a WebView document request. The WebView renders that HTML as a page, executes its scripts and loads its resources. The application does not need to insert HTML into an existing DOM or display it in an iframe. +This path is for a developer who has a Workers web app and wants to add a mobile +version. Capacitor supplies the native projects; cf-workers-native connects the +existing Worker pages and requests to them. -```text -WebView opens /notes at the app's local origin - → the library receives the document request - → generated dispatch selects local or remote execution - local: the existing Fetch handler runs on the device - remote: the request goes to the existing deployed Worker - → response status, headers and HTML body return through the document bridge - → WebView renders the page -``` +Have these ready: -Both execution paths use the same document response mechanism. A D1-backed page can retain authentication, its query and SSR on the remote Worker; a compatible independent page can render locally. The build may select the entire Worker for remote execution when safe separation is not possible. This is request dispatch, not moving D1 operations individually between runtimes. +- Your application's source and a working web build. For a first example, use [Hono / Express pages](../demo/rendering/README.md) or [Void + D1](../demo/void/README.md). +- A deployed **test** Worker URL for cloud-backed pages, data and authentication. Keep D1 and server credentials on that Worker. +- Node and the platform development tools: macOS with Xcode for iOS, or the Android toolchain for Android. Follow [Capacitor's environment setup](https://capacitorjs.com/docs/getting-started/environment-setup) and your framework's version requirements. +- An application name and ID for the mobile projects. A simulator or emulator is enough for the first run. -Following an ordinary link produces the next document request through the same mechanism. Supported form submissions and same-origin redirects also retain document navigation. Existing client scripts can provide interaction or hydration where the framework uses it. Bundled assets bypass the Worker router; other requests follow their configured routing. Preserve the application's existing page model before considering any redesign. +The first milestone is an existing page displayed in the app, a link that navigates, +and a form or data action that succeeds. Then verify the full flow, including +login and session handling, in [the acceptance checklist](#6-verify-the-existing-application-in-capacitor). +Web authentication may need mobile callback configuration; assess it in your app. -On iOS the bridge uses `WKURLSchemeHandler`; on Android it uses a Service Worker. The visible page keeps the app-local URL (normally `capacitor://localhost` on iOS and `https://localhost` on Android), while the Worker receives its logical HTTP(S) URL. This is native document rendering, not a remote browser tab or a local HTTP server. See the [native rendering guide](native-rendering-api.md) for form, redirect, asset and lifecycle limits; this does not guarantee every browser or framework feature. +This guide requires a mobile build configuration and native project setup. +Signing, store accounts, submission and review come after the application works. ## Prompt to give your AI assistant @@ -382,3 +383,23 @@ Test the target iOS and Android platforms using an actual user flow: - Run the application's existing cloud tests to check that integration has not changed its server behavior. Browser tests do not replace native navigation/session tests. Report the integration files added, each necessary application change and its reason, commands executed, tested platforms, execution boundaries and remaining limitations. Distinguish simulator/emulator checks from physical-device checks, and remote execution from local compatibility. If there is no deployed test backend or native SDK available, state what could and could not be verified rather than claiming completion. + +## How existing Worker pages reach the screen + +With `render`, the library supplies the Worker's response as the response to a WebView document request. The WebView renders that HTML as a page, executes its scripts and loads its resources. The application does not need to insert HTML into an existing DOM or display it in an iframe. + +```text +WebView opens /notes at the app's local origin + → the library receives the document request + → generated dispatch selects local or remote execution + local: the existing Fetch handler runs on the device + remote: the request goes to the existing deployed Worker + → response status, headers and HTML body return through the document bridge + → WebView renders the page +``` + +Both execution paths use the same document response mechanism. A D1-backed page can retain authentication, its query and SSR on the remote Worker; a compatible independent page can render locally. The build may select the entire Worker for remote execution when safe separation is not possible. This is request dispatch, not moving D1 operations individually between runtimes. + +Following an ordinary link produces the next document request through the same mechanism. Supported form submissions and same-origin redirects also retain document navigation. Existing client scripts can provide interaction or hydration where the framework uses it. Bundled assets bypass the Worker router; other requests follow their configured routing. Preserve the application's existing page model before considering any redesign. + +On iOS the bridge uses `WKURLSchemeHandler`; on Android it uses a Service Worker. The visible page keeps the app-local URL (normally `capacitor://localhost` on iOS and `https://localhost` on Android), while the Worker receives its logical HTTP(S) URL. This is native document rendering, not a remote browser tab or a local HTTP server. See the [native rendering guide](native-rendering-api.md) for form, redirect, asset and lifecycle limits; this does not guarantee every browser or framework feature.