Skip to content

Native Capacitor examples for Meteor - #47

Open
nachocodoner wants to merge 37 commits into
mainfrom
feat/capacitor-mobile-examples
Open

Native Capacitor examples for Meteor#47
nachocodoner wants to merge 37 commits into
mainfrom
feat/capacitor-mobile-examples

Conversation

@nachocodoner

@nachocodoner nachocodoner commented Jul 31, 2026

Copy link
Copy Markdown
Member

Related: https://forums.meteor.com/t/capacitorjs-is-coming-to-meteor-as-its-modern-native-stack/64722 and meteor/meteor#14633

This PR adds three complete native examples to meteor/examples, showing how Meteor's web and data workflow runs inside Capacitor-managed Android and iOS projects.

Warning

Meteor's Capacitor integration is experimental and under active development. Native commands, plugin and runtime interfaces, HCP behavior, and generated project setup can change. These examples are working references and testbeds, not compatibility guarantees; update them as integration behavior changes.

See Native Stack overview for Capacitor and legacy Cordova choices, and Capacitor mobile guide for setup, configuration, platforms, modes, plugins, and production builds.

Each app uses Meteor's integration directly:

  • Meteor builds the client bundle and owns data, DDP, and Hot Code Push (HCP).
  • Capacitor owns native projects, plugin bridge, device APIs, and toolchain.
  • meteor run android and meteor run ios build, synchronize, and launch the selected target.

The examples cover a real-time game, focused utility, and offline field workflow, providing complete code to run, inspect, and adapt.

Each application uses a touch-optimized web UI library: Konsta UI for game navigation, MUI for responsive phone and tablet controls, and Framework7 React for native-feeling field workflows. They run inside the Capacitor WebView, while Capacitor provides device APIs and native integration.

  • Meteor Drop: a four-in-a-row game with solo and live multiplayer play.
  • Stock Scanner: a camera-first inventory audit application.
  • Civic Snap: a neighbourhood issue reporting workflow with offline submission.
  • Shared launcher: installs local Meteor packages, links runtime, prepares native projects, and runs Android or iOS.
  • Test flows: Maestro native smoke and showcase coverage, plus Playwright browser coverage.

All apps use React and Rspack, ship capacitor.config.js, enable HCP, expose runtime/DDP/HCP diagnostics, and protect native behavior with browser-safe adapters.

Applications

Meteor Drop

Purpose: mobile four-in-a-row game with local CPU play and live rooms.

Why: exercises a real-time workload, using reactive DDP updates to synchronize live game boards.

Stack: Meteor, Rspack, React, Konsta UI, MongoDB, Capacitor App, Haptics, Network, Share, Meteor Capacitor HCP, Mocha, oxlint, Playwright, and Maestro.

What it showcases: Konsta UI mobile navigation, game interaction, live room state over DDP, CPU and multiplayer modes, network state, native haptics and sharing, Android back-button decisions, and native update diagnostics.

Demo

meteor-drop-ios-functionality-and-real-hcp.mp4

Stock Scanner

Purpose: inventory auditing through barcode scans, category-aware stock state, count adjustments, and shared summaries.

Why: keeps product scope narrow so scanning, haptic feedback, sharing, and responsive MUI navigation remain easy to inspect.

Stack: Meteor, Rspack, React, MUI, MongoDB, Capacitor App, Barcode Scanner, Haptics, Share, Meteor Capacitor HCP, Mocha, oxlint, Playwright, and Maestro.

What it showcases: MUI responsive phone and tablet controls, camera-first UI, Android back handling, barcode permissions, native action feedback, native app metadata, browser fallbacks, and visible runtime, DDP, and HCP state.

Demo stock-scanner-ios-poster

Civic Snap

Purpose: neighbourhood issue reporting with evidence capture, location, submission, and status tracking.

Why: covers a broader field workflow with device permissions, offline submission, and Meteor synchronization after reconnection.

Stack: Meteor, Rspack, React, Framework7 React, MongoDB, jam:offline, jam:method, jam:pub-sub, Capacitor App, Camera, Geolocation, Network, Local Notifications, Share, Meteor Capacitor HCP, Mocha, oxlint, Playwright, and Maestro.

What it showcases: Framework7 React native-feeling navigation, camera and photo-library capture, location permission handling, network awareness, local notifications, offline-first Meteor methods and publications, native sharing, and HCP consent flow.

Demo city-issue-reporter-ios-poster

Shared native architecture

Each app keeps clear native boundaries:

  • capacitor.config.js uses defineConfig for app identity and options; Meteor adds platform, mode, web directory, server, and splash-screen defaults.
  • Plugin modules check Capacitor.isNativePlatform() and provide browser-safe behavior.
  • meteor.capacitor.hcp uses webapp. Bundled runs start locally, then HCP can switch to a newer web bundle. See Capacitor Hot Code Push.
  • Meteor creates or updates standard Capacitor projects and synchronizes them during native commands.

Hands-on

Run one example with launcher

meteor/examples includes a launcher for demos and local development. It checks Meteor checkout branch, installs and links local packages, adds missing platform, applies app-specific setup, and runs Meteor.

The launcher requires Node, a runnable Meteor checkout, and platform prerequisites. It does not install Android SDK, Xcode, emulators, or Simulators.

Clone both repositories on matching branches first. Launcher never clones, fetches, pulls, or switches branches.

mkdir meteor-native-workspace
cd meteor-native-workspace

git clone --branch feat/capacitor-mobile-examples \
  https://github.com/meteor/examples.git examples
git clone --branch capacitor-integration \
  https://github.com/meteor/meteor.git meteor

cd examples

From meteor/examples:

# Android
npm run run:native -- meteor-drop android

# iOS, macOS only
npm run run:native -- meteor-drop ios

# Per-app shortcut
npm run run:native:meteor-drop -- android

The launcher defaults to bundled development mode, not livereload. Application starts from local assets with HCP active, then can switch to a newer bundle when Meteor server is reachable. Use -- --production only to validate a production bundle.

Pass Meteor options after --. Android emulator commonly needs 10.0.2.2 to reach host Meteor server:

npm run run:native -- meteor-drop android -- --mobile-server http://10.0.2.2:3000

Run npm run run:native -- --help for all options. Apps: meteor-drop, stock-scanner, and civic-snap; platforms: android and ios.

Custom checkout layouts and branches

Launcher defaults to sibling Meteor checkout at ../meteor:

parent-directory/
  meteor/     # Meteor source checkout
  examples/   # meteor/examples checkout

For another layout, use METEOR_CHECKOUT or --meteor-checkout:

METEOR_CHECKOUT=/absolute/path/to/meteor \
  npm run run:native -- meteor-drop android
npm run run:native -- meteor-drop android \
  --meteor-checkout /absolute/path/to/meteor

For another Meteor branch, keep the checkout guard and set the expected branch:

npm run run:native -- meteor-drop android \
  --meteor-checkout /absolute/path/to/meteor \
  --expected-branch my-capacitor-change

Manual setup and Meteor core contributor workflow

Use manual path to understand launcher, adapt another application, or contribute to Meteor integration. It runs local Meteor and links local @meteorjs/capacitor and @meteorjs/rspack, so core changes reach examples without npm publication.

For core architecture and generic application setup, see Meteor core PR manual setup.

Show manual contributor setup

1. Prepare Meteor checkout

Use a Meteor source checkout containing the integration. The launcher expects capacitor-integration by default.

git clone https://github.com/meteor/meteor.git /absolute/path/to/meteor
cd /absolute/path/to/meteor
git switch capacitor-integration
# Git older than 2.23: git checkout capacitor-integration
./meteor --version

export METEOR_CHECKOUT="$PWD"
export METEOR_BIN="$METEOR_CHECKOUT/meteor"

Follow Native Pre-Installation for Android SDK, Java, Gradle, Xcode, CocoaPods, emulator, and Simulator. iOS requires macOS.

2. Link local Capacitor packages

Link checkout packages so examples run current integration code instead of published npm versions.

cd /absolute/path/to/examples/stock-scanner

"$METEOR_BIN" npm install --no-audit --no-fund --no-save --package-lock=false \
  "$METEOR_CHECKOUT/npm-packages/meteor-capacitor" \
  "$METEOR_CHECKOUT/npm-packages/meteor-rspack"

npm link --no-save \
  "$METEOR_CHECKOUT/npm-packages/meteor-capacitor" \
  "$METEOR_CHECKOUT/npm-packages/meteor-rspack"

For a new application, add the Capacitor package:

"$METEOR_BIN" add capacitor

With automatic npm installation enabled, the first platform or run command installs missing @capacitor/core, @capacitor/cli, @meteorjs/capacitor, and the selected package such as @capacitor/android or @capacitor/ios. Install them manually only if automation is disabled or fails. Capacitor mobile guide explains this lifecycle.

The first add-platform, native run, or native build command also creates a default capacitor.config.js when none exists. Review its generated identity before distribution. To customize it before the first command, create the file yourself:

// capacitor.config.js
const { defineConfig } = require('@meteorjs/capacitor');

module.exports = defineConfig(() => ({
  appId: 'com.example.myapp',
  appName: 'My App',
  ios: { contentInset: 'always' },
}));

Use a unique reverse-DNS appId before distribution.

3. Add native platform

Run once per platform. Meteor creates the missing native project and synchronizes later runs.

# Android
"$METEOR_BIN" add-platform android

# iOS, macOS only
"$METEOR_BIN" add-platform ios

4. Run Android or iOS

# Default: development build starts from bundled local assets; HCP stays active.
"$METEOR_BIN" run android
"$METEOR_BIN" run ios

Bundled HCP works in development and production. For Android emulator, pass same --mobile-server option shown in launcher path when explicit server URL is needed.

Livereload is opt-in for direct-server UI iteration. It does not test bundled startup or HCP; device or emulator must reach Meteor server:

METEOR_CAPACITOR_MODE=livereload "$METEOR_BIN" run PLATFORM \
  --mobile-server http://HOST_IP:3000

Replace PLATFORM with android or ios, and HOST_IP with development machine address reachable from device or emulator.

5. Add native plugin

Install a plugin through npm, import it, then rerun the native command. Meteor runs cap sync, applying plugin changes to the native project.

"$METEOR_BIN" npm install @capacitor/device
"$METEOR_BIN" run android
import { Device } from '@capacitor/device';

const info = await Device.getInfo();

See Capacitor mobile guide for plugin imports, browser fallbacks, configuration, HCP, and production builds.

Test and showcase coverage

Each app has unit tests for native adapters and HCP, Playwright browser and native-shaped UI coverage, and Maestro Android and iOS smoke and showcase flows.

# Launcher unit tests
npm run test:native:unit

# Maestro smoke flow
npm run test:native:stock-scanner:android

# Record showcase media
npm run record:native:civic-snap:ios

Follow-up

Use these apps as starting points: choose focused utility, offline workflow, or live-data game; copy native adapter pattern; add plugins through standard npm and Meteor commands. Test both new applications and Cordova migrations, then share gaps, plugin compatibility results, and reproducible issues.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant