Comprehensive plan for wrapping bitvid as native apps using Capacitor for Android, iOS, and desktop (Windows/macOS/Linux via Electron). Covers architecture, phased implementation, CI/CD workflows, testing strategy, platform risks, and app store submission guidance. https://claude.ai/code/session_01RBdcFkjzXaawaLY68MMhxc
32 KiB
Capacitor Native App Plan
Status: Planning Platforms: Android, iOS, Windows, macOS, Linux Framework: Capacitor by Ionic Goal: Ship bitvid as a native app on all major platforms while keeping a single codebase with the existing web/PWA deployment.
Table of Contents
- Why Capacitor
- Architecture Overview
- Repository Structure
- Phase 1 — Foundation
- Phase 2 — Android & iOS
- Phase 3 — Desktop (Electron via Capacitor)
- Phase 4 — Platform-Specific Enhancements
- Phase 5 — CI/CD for Native Builds
- Phase 6 — Testing Strategy
- Platform Considerations & Risks
- App Store Strategy
- Task Checklist
Why Capacitor
Fit for bitvid
bitvid is a fully static, client-side web application. There is no backend server — all authentication, data, and state management happens in the browser via Nostr relays and WebTorrent. This makes it an ideal candidate for Capacitor, which wraps an existing web app in a native WebView shell.
Key reasons
| Reason | Detail |
|---|---|
| Zero rewrite | The existing dist/ build output drops directly into Capacitor as the web layer. No framework migration needed. |
| Single codebase | Web, PWA, Android, iOS, and desktop all share the same HTML/CSS/JS. Platform-specific behavior is handled via feature detection and Capacitor's plugin bridge. |
| Progressive native access | Start with a pure web wrapper, then incrementally add native plugins (deep links, push notifications, share targets, file system) only when needed. |
| Mature mobile support | Capacitor has first-class Android and iOS support with a large plugin ecosystem. |
| Desktop via Electron | The @nicepkg/capacitor-electron community plugin (or the @nicepkg/cap-electron plugin) lets Capacitor drive an Electron shell for Windows/macOS/Linux using the same web build. |
| Existing PWA foundation | bitvid already has site.webmanifest, a service worker (sw.min.js), and app icons — all of which Capacitor respects and builds on. |
| Active ecosystem | Large community, official Ionic backing, regular releases, good documentation. |
Alternatives considered
| Framework | Why not primary |
|---|---|
| Tauri | Excellent for desktop (small binaries, Rust backend), but mobile support is still in beta. Could be revisited later as a desktop-only option if Electron bundle size becomes a concern. |
| Electron standalone | Bundles ~150MB of Chromium per platform. Capacitor+Electron gives us the same result but with a unified build pipeline across all platforms. |
| React Native / Flutter | Would require a complete rewrite. bitvid is vanilla JS with no component framework — porting to RN or Flutter would be a ground-up rebuild. |
| PWA only | Already partially implemented. Good for web-savvy users but lacks app store discoverability, has weaker iOS support (no push notifications, limited background execution), and misses users who expect a "real" app install. |
Architecture Overview
┌─────────────────────────────────────────────────────┐
│ bitvid codebase │
│ │
│ ┌───────────┐ npm run build ┌───────────────┐ │
│ │ Source │ ────────────────→ │ dist/ │ │
│ │ (js/, │ │ (static web │ │
│ │ css/, │ │ assets) │ │
│ │ views/) │ └──────┬────────┘ │
│ └───────────┘ │ │
│ │ │
│ ┌────────────────┼─────┐ │
│ │ npx cap sync │ │ │
│ ▼ ▼ ▼ │
│ ┌─────────┐ ┌─────┐ ┌────────┐ │
│ │ android/│ │ ios/│ │electron/│ │
│ │ (native │ │ │ │ │ │
│ │ project)│ │ │ │ │ │
│ └─────────┘ └─────┘ └────────┘ │
│ │
│ Deploy targets: │
│ • Web/PWA → dist/ served via Netlify/Vercel/etc │
│ • Android → android/ → Play Store APK/AAB │
│ • iOS → ios/ → App Store IPA │
│ • Desktop → electron/ → Windows/macOS/Linux │
└─────────────────────────────────────────────────────┘
Data flow (unchanged)
The native shell is purely a container. All app logic remains in the web layer:
- User action triggers a UI controller event handler
- Controller invokes callback provided by
bitvidApp bitvidAppexecutes logic, communicates with Nostr relays via WebSocket- WebTorrent handles P2P video streaming via WebRTC data channels
- UI updates via DOM manipulation
The only new data path is the Capacitor bridge — a thin JS-to-native channel used for:
- Deep link handling (Nostr URIs,
nostr:protocol) - Push notification tokens (optional, future)
- Native share sheet integration
- App lifecycle events (background/foreground)
- Status bar / navigation bar styling
Repository Structure
The native project directories live at the repo root alongside the existing web source. This is the standard Capacitor monorepo layout.
bitvid/
├── android/ # NEW — Native Android project (Android Studio)
│ ├── app/
│ │ ├── src/main/
│ │ │ ├── AndroidManifest.xml
│ │ │ ├── java/com/bitvid/app/
│ │ │ └── res/
│ │ └── build.gradle
│ ├── capacitor.settings.gradle
│ └── build.gradle
├── ios/ # NEW — Native iOS project (Xcode)
│ └── App/
│ ├── App/
│ │ ├── AppDelegate.swift
│ │ ├── Info.plist
│ │ └── capacitor.config.json (generated)
│ ├── App.xcodeproj
│ └── Podfile
├── electron/ # NEW — Electron desktop shell
│ ├── src/
│ │ ├── index.ts
│ │ └── preload.ts
│ ├── capacitor.config.ts
│ └── package.json
├── capacitor.config.ts # NEW — Capacitor root config
├── dist/ # Existing build output (web assets)
├── js/ # Existing source
├── css/ # Existing source
├── config/
│ └── instance-config.js # Extended with platform detection
├── scripts/
│ ├── build-dist.mjs # Existing web build
│ ├── build-android.mjs # NEW — Android build helper
│ ├── build-ios.mjs # NEW — iOS build helper
│ └── build-desktop.mjs # NEW — Electron build helper
├── tests/
│ ├── unit/ # Existing
│ ├── e2e/ # Existing (web)
│ ├── visual/ # Existing
│ ├── native/ # NEW — Native-specific tests
│ │ ├── android/
│ │ ├── ios/
│ │ └── desktop/
│ └── platform/ # NEW — Cross-platform behavior tests
├── .github/workflows/
│ ├── ci.yml # Existing (web CI)
│ ├── ci-android.yml # NEW — Android build + test
│ ├── ci-ios.yml # NEW — iOS build + test
│ └── ci-desktop.yml # NEW — Electron build + test
├── package.json # Extended with native scripts
├── capacitor.config.ts # Capacitor root configuration
└── site.webmanifest # Existing PWA manifest
What gets gitignored
# Native build artifacts
android/app/build/
android/.gradle/
android/capacitor-cordova-android-plugins/build/
ios/App/Pods/
ios/App/DerivedData/
electron/dist/
electron/node_modules/
# Capacitor copies of web assets (regenerated by cap sync)
android/app/src/main/assets/public/
ios/App/App/public/
What gets committed
The native project scaffolding (android/, ios/, electron/) is committed to the repo. This is the Capacitor convention — the native projects are source code, not generated artifacts. They contain platform-specific configuration (permissions, entitlements, splash screens, icons) that must be version-controlled.
Phase 1 — Foundation
Goal: Initialize Capacitor, get the web app running inside native shells on Android and iOS simulators, and Electron on desktop.
Tasks
-
Install Capacitor core
npm install @capacitor/core @capacitor/cli -
Create
capacitor.config.tsimport type { CapacitorConfig } from '@capacitor/cli'; const config: CapacitorConfig = { appId: 'com.bitvid.app', appName: 'bitvid', webDir: 'dist', server: { // Allow WebSocket connections to Nostr relays allowNavigation: ['*'], }, plugins: { SplashScreen: { launchShowDuration: 2000, backgroundColor: '#0f172a', // matches theme }, }, }; export default config; -
Add native platforms
npx cap add android npx cap add ios -
Update build pipeline — extend
build-dist.mjsor add a wrapper:npm run build && npx cap syncThe
cap synccommand copiesdist/into each native project and updates native dependencies. -
Add Electron support via community plugin:
npm install @nicepkg/capacitor-electron npx cap add electron -
Add npm scripts
{ "scripts": { "cap:sync": "npx cap sync", "cap:android": "npm run build && npx cap sync android && npx cap open android", "cap:ios": "npm run build && npx cap sync ios && npx cap open ios", "cap:electron": "npm run build && npx cap sync electron && npx cap open electron", "build:all": "npm run build && npx cap sync" } } -
Verify basic functionality
- App loads in Android emulator
- App loads in iOS simulator
- App loads in Electron window
- Nostr relay WebSocket connections work
- Theme renders correctly
- Navigation / SPA routing works
Platform detection helper
Add a lightweight platform detection utility that the rest of the app can use:
// js/utils/platform.js
import { Capacitor } from '@capacitor/core';
export const platform = {
isNative: Capacitor.isNativePlatform(),
isAndroid: Capacitor.getPlatform() === 'android',
isIos: Capacitor.getPlatform() === 'ios',
isElectron: Capacitor.getPlatform() === 'electron',
isWeb: Capacitor.getPlatform() === 'web',
};
This module is safe to import on web — @capacitor/core detects it's running in a browser and returns 'web' for the platform.
Phase 2 — Android & iOS
Goal: Production-quality mobile builds ready for app store submission.
Android-specific work
-
Permissions in
AndroidManifest.xml:INTERNET(already default)ACCESS_NETWORK_STATE(connectivity detection)CAMERA/MICROPHONE— only if video recording is added later (not needed now)
-
WebView configuration:
- Enable mixed content mode (for WebSocket
wss://alongsidehttps://) - Enable JavaScript (default in Capacitor)
- Set
webSettings.mediaPlaybackRequiresUserGesture = falsefor autoplay
- Enable mixed content mode (for WebSocket
-
App icons and splash screens:
- Use
@capacitor/splash-screenplugin - Generate from existing
assets/png/android-chrome-512x512.png - Use
cordova-resor@capacitor/assetsto generate all density variants
- Use
-
Deep links:
- Register
nostr:URI scheme via Android intent filters - Register
https://bitvid.tvdomain for App Links (needs.well-known/assetlinks.json)
- Register
-
Status bar and navigation bar:
@capacitor/status-barplugin to match the dark theme (#0f172a)- Handle safe areas / notch insets via CSS
env(safe-area-inset-*)
iOS-specific work
-
Info.plist configuration:
NSAppTransportSecurity— allow WebSocket connections- App description strings for any permission prompts
-
WKWebView settings:
allowsInlineMediaPlayback: truemediaTypesRequiringUserActionForPlayback: [](enables autoplay)- These are configurable in
capacitor.config.tsunderios.webContentsConfiguration
-
Deep links:
- Universal Links (needs
apple-app-site-associationon the domain) - Custom URL scheme
bitvid://
- Universal Links (needs
-
Safe areas:
- iOS notch, Dynamic Island, home indicator
- CSS
env(safe-area-inset-top)etc. — update layout inindex.htmland key UI components
-
App icons:
- Generate full icon set from existing 512x512 source
- Must include 1024x1024 for App Store
Shared mobile work
-
Hardware back button (Android):
- Handle back navigation within the SPA instead of exiting the app
- Use
@capacitor/appplugin'sbackButtonlistener
-
App lifecycle:
- Pause/resume WebSocket connections on app background/foreground
- Use
@capacitor/appappStateChangelistener
-
Keyboard handling:
- Adjust layout when virtual keyboard appears (search bar, comment inputs)
- Capacitor provides
Keyboardplugin for this
-
Haptic feedback (optional):
- Light haptics on zap actions using
@capacitor/haptics
- Light haptics on zap actions using
Phase 3 — Desktop (Electron via Capacitor)
Goal: Ship bitvid as a standalone desktop app for Windows, macOS, and Linux.
Approach
Use Capacitor's Electron integration so the desktop build uses the same dist/ web assets and the same Capacitor plugin bridge as mobile.
Desktop-specific work
-
Window configuration:
- Default size: 1280x800 (fits well for video content)
- Minimum size: 800x600
- Remember window position/size across launches
- Frameless window option with custom title bar (matches bitvid header)
-
Menu bar:
- Minimal native menu (File, Edit, View, Help)
- Or hide native menu and use the web app's own navigation
-
Tray icon (optional):
- System tray icon for background seeding (WebTorrent)
- "Minimize to tray" behavior
-
Auto-updater:
- Electron's
autoUpdaterfor seamless desktop updates - Or use GitHub Releases as the update feed
- Electron's
-
Protocol handler:
- Register
nostr:andbitvid:URI schemes at OS level
- Register
-
Packaging:
- Windows: NSIS installer or MSIX
- macOS: DMG + notarization
- Linux: AppImage, .deb, .rpm
Phase 4 — Platform-Specific Enhancements
These are optional features that improve the native experience. Implement after core functionality is solid.
Native share sheet
import { Share } from '@capacitor/share';
async function shareVideo(video) {
if (platform.isNative) {
await Share.share({
title: video.title,
text: video.description,
url: `https://bitvid.tv/#video/${video.id}`,
dialogTitle: 'Share video',
});
}
}
Push notifications (future)
Nostr-based push could be implemented via:
- A lightweight push relay that watches for mentions/zaps and sends FCM/APNs
@capacitor/push-notificationsplugin to receive them
This is a significant feature and should be its own planning document.
Offline support
- Cache the app shell and critical assets in the service worker
- Cache recently viewed video metadata for offline browsing
- Queue zaps and reactions for when connectivity returns
Picture-in-picture
- Android: native PiP mode via custom Capacitor plugin
- iOS:
AVPictureInPictureControllervia the WebView's native video player - Desktop: Electron
BrowserWindowPiP API
Phase 5 — CI/CD for Native Builds
New CI workflows
ci-android.yml
name: CI — Android
on:
push:
branches: [main]
paths:
- 'js/**'
- 'css/**'
- 'views/**'
- 'components/**'
- 'android/**'
- 'capacitor.config.ts'
- 'package.json'
pull_request:
paths:
- 'js/**'
- 'css/**'
- 'views/**'
- 'components/**'
- 'android/**'
- 'capacitor.config.ts'
jobs:
build-android:
runs-on: ubuntu-latest
timeout-minutes: 30
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 22
- uses: actions/setup-java@v4
with:
distribution: 'temurin'
java-version: '17'
- name: Install dependencies
run: npm ci
- name: Build web assets
run: npm run build
- name: Sync Capacitor
run: npx cap sync android
- name: Build Android debug APK
working-directory: android
run: ./gradlew assembleDebug
- name: Upload APK artifact
uses: actions/upload-artifact@v4
with:
name: bitvid-android-debug
path: android/app/build/outputs/apk/debug/app-debug.apk
ci-ios.yml
name: CI — iOS
on:
push:
branches: [main]
paths: ['js/**', 'css/**', 'views/**', 'ios/**', 'capacitor.config.ts']
pull_request:
paths: ['js/**', 'css/**', 'views/**', 'ios/**', 'capacitor.config.ts']
jobs:
build-ios:
runs-on: macos-latest
timeout-minutes: 45
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 22
- name: Install dependencies
run: npm ci
- name: Build web assets
run: npm run build
- name: Sync Capacitor
run: npx cap sync ios
- name: Install CocoaPods
working-directory: ios/App
run: pod install
- name: Build iOS (no sign)
run: |
xcodebuild build \
-workspace ios/App/App.xcworkspace \
-scheme App \
-destination 'generic/platform=iOS Simulator' \
CODE_SIGN_IDENTITY="" \
CODE_SIGNING_REQUIRED=NO
ci-desktop.yml
name: CI — Desktop
on:
push:
branches: [main]
paths: ['js/**', 'css/**', 'views/**', 'electron/**', 'capacitor.config.ts']
pull_request:
paths: ['js/**', 'css/**', 'views/**', 'electron/**', 'capacitor.config.ts']
jobs:
build-desktop:
strategy:
matrix:
os: [ubuntu-latest, windows-latest, macos-latest]
runs-on: ${{ matrix.os }}
timeout-minutes: 30
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 22
- name: Install dependencies
run: npm ci
- name: Build web assets
run: npm run build
- name: Sync Capacitor
run: npx cap sync electron
- name: Build Electron
working-directory: electron
run: npm run build
Path-filtered triggers
Each native CI workflow uses paths filters so that:
- A CSS-only change triggers Android + iOS + Desktop builds (the web layer changed)
- A change to only
android/triggers just the Android build - Existing web CI (
ci.yml) continues to run independently
CI cost management
Native CI is more expensive than web CI:
- iOS builds require
macos-latestrunners (2-3x cost on GitHub Actions) - Android builds need JDK + Gradle (slower startup)
- Desktop builds run on 3 OS matrix entries
To manage costs:
- Only run native CI on PRs that touch relevant paths
- Cache Gradle/CocoaPods/node_modules aggressively
- Consider running iOS CI only on
mainmerges (not every PR) initially - Use GitHub Actions concurrency groups with
cancel-in-progress: true
Phase 6 — Testing Strategy
Testing layers
┌─────────────────────────────────────────────┐
│ Unit Tests (existing) │ ← Platform-agnostic
│ vitest — js logic, nostr, schemas, utils │ No changes needed
├─────────────────────────────────────────────┤
│ Visual Regression (existing) │ ← Web viewport
│ Playwright — screenshot comparison │ Add mobile viewports
├─────────────────────────────────────────────┤
│ E2E Web (existing) │ ← Browser-based
│ Playwright — user journeys in Chrome │ No changes needed
├─────────────────────────────────────────────┤
│ E2E Mobile (NEW) │ ← Device/emulator
│ Appium or Detox — native app user flows │
├─────────────────────────────────────────────┤
│ Platform Smoke Tests (NEW) │ ← Quick validation
│ Per-platform build + launch + basic checks │
├─────────────────────────────────────────────┤
│ Cross-Platform Behavior Tests (NEW) │ ← Feature parity
│ Verify features work consistently across │
│ web, Android, iOS, and desktop │
└─────────────────────────────────────────────┘
New test categories
Platform smoke tests (tests/native/)
Quick checks that run after each native build:
- App launches without crash
- Main view renders
- WebSocket connection to a relay succeeds
- Video playback starts (URL source)
- Theme renders correctly (screenshot comparison)
Mobile viewport visual tests
Extend existing Playwright visual tests with mobile viewports:
// playwright.config.ts addition
projects: [
// existing desktop viewports...
{
name: 'Mobile Android',
use: { ...devices['Pixel 7'] },
},
{
name: 'Mobile iOS',
use: { ...devices['iPhone 14'] },
},
]
This runs in Playwright's browser emulation (not on real devices) but catches responsive layout issues early.
WebView-specific E2E tests
For testing inside the actual native WebView (not just a browser), use:
- Android: Espresso + WebView assertions, or Appium with WebView context switching
- iOS: XCUITest + WebView inspection, or Appium
These are heavier to set up but catch WebView-specific issues (service worker behavior, WebRTC in WKWebView, etc).
What to test per platform
| Test | Web | Android | iOS | Desktop |
|---|---|---|---|---|
| Unit tests | yes | n/a | n/a | n/a |
| Visual regression (browser) | yes | mobile viewport | mobile viewport | yes |
| E2E web journeys | yes | — | — | — |
| App launches | — | yes | yes | yes |
| Relay WebSocket connects | yes | yes | yes | yes |
| Video playback (URL) | yes | yes | yes | yes |
| Video playback (WebTorrent) | yes | yes | test carefully | yes |
Deep links (nostr:) |
— | yes | yes | yes |
| Back button navigation | — | yes | — | — |
| Safe area rendering | — | — | yes | — |
| Keyboard interaction | — | yes | yes | — |
| Offline behavior | yes | yes | yes | yes |
Platform Considerations & Risks
WebTorrent on iOS (HIGH RISK)
Issue: WKWebView's WebRTC support is more limited than desktop Chrome. WebTorrent relies on WebRTC data channels for peer-to-peer streaming.
Mitigation:
- bitvid already has a URL-first playback fallback (
DEFAULT_PLAYBACK_SOURCEin instance config) - For iOS builds, default to URL-first playback:
DEFAULT_PLAYBACK_SOURCE: 'url' - Use platform detection to set this automatically:
if (platform.isIos) { setUrlFirstEnabled(true); } - Test WebTorrent streaming on real iOS devices — it may work in modern iOS versions (16+), but should not be the primary path
Service worker in Capacitor WebView
Issue: The sw.min.js service worker intercepts fetch requests to proxy WebTorrent stream data. Service worker support in native WebViews varies.
Mitigation:
- Android: WKWebView supports service workers (API level 33+). For older Android, the URL fallback handles it.
- iOS: WKWebView supports service workers in iOS 14+, but with some caveats around scope and lifecycle.
- Test the WebTorrent streaming service worker flow specifically in native WebViews.
- If service worker is unreliable, consider a Capacitor plugin that bridges native HTTP interception as an alternative stream proxy.
WebSocket connectivity
Issue: Native platforms may restrict background WebSocket connections.
Mitigation:
- Use
@capacitor/applifecycle events to gracefully disconnect/reconnect:App.addListener('appStateChange', ({ isActive }) => { if (isActive) { nostrClient.reconnect(); } else { nostrClient.pause(); } }); - This also reduces battery drain from idle relay connections.
Content Security Policy
Issue: Capacitor serves web assets from a local origin (capacitor://localhost on iOS, https://localhost on Android). CSP rules may need adjustment.
Mitigation:
- Update
_headers/ CSP meta tags to allow the Capacitor local origin - Allow
wss://*for Nostr relay connections - Allow
blob:anddata:for WebTorrent stream playback
App Store rejection risk
See the App Store Strategy section below.
App Store Strategy
Google Play Store
Risk level: Low-Medium
Google is generally more permissive. Key considerations:
- Content rating: Declare user-generated content (UGC) in the rating questionnaire
- Moderation: bitvid's existing moderation system (NIP-56 reports, NIP-51 mute lists, blur thresholds, autoplay blocking) demonstrates active content moderation
- Crypto/payments: Lightning/Zap functionality may trigger financial services review. Frame it as "tips" or "donations", not as a payment system. Emphasize that bitvid does not custody funds.
Apple App Store
Risk level: Medium-High
Apple has been unpredictable with Nostr/decentralized apps. Key considerations:
- Guideline 4.2 (Minimum Functionality): The app must provide functionality beyond a "repackaged website". Native features (deep links, share sheet, haptics, PiP) help differentiate.
- Guideline 1.2 (User Generated Content): Must have content reporting, blocking, and moderation. bitvid already has this.
- Guideline 3.1.1 (In-App Purchase): If Lightning zaps are interpreted as digital purchases, Apple may require IAP. Mitigation: frame zaps as peer-to-peer tips external to the app (similar to how other Nostr apps handle this).
- Review strategy: Submit early with a clear App Review note explaining the decentralized architecture and content moderation approach. Engage with the review team proactively.
Desktop distribution
Risk level: Low
- Windows: Distribute via GitHub Releases initially. Microsoft Store submission optional.
- macOS: Notarize the DMG with an Apple Developer account. Distribute via GitHub Releases or the Mac App Store.
- Linux: AppImage on GitHub Releases. Snap Store / Flathub optional.
Task Checklist
Phase 1 — Foundation
- Install
@capacitor/coreand@capacitor/cli - Create
capacitor.config.tswith bitvid app ID and config - Run
npx cap add androidand verify project structure - Run
npx cap add iosand verify project structure - Set up Electron via community Capacitor plugin
- Add
js/utils/platform.jsplatform detection utility - Update
package.jsonwith Capacitor scripts (cap:sync,cap:android,cap:ios,cap:electron) - Update
.gitignorefor native build artifacts - Verify web app loads in Android emulator
- Verify web app loads in iOS simulator
- Verify web app loads in Electron window
- Verify Nostr relay connections work on all platforms
- Document local development setup for native builds
Phase 2 — Android & iOS
- Configure Android permissions in
AndroidManifest.xml - Configure iOS
Info.plistsettings - Generate app icons for all densities (Android + iOS)
- Generate splash screens
- Implement safe area CSS for iOS notch / Dynamic Island
- Add
@capacitor/status-barand theme it to match bitvid - Add
@capacitor/appfor lifecycle events (background/foreground) - Implement hardware back button handling (Android)
- Set up deep link handling for
nostr:URIs - Configure WebView settings for media autoplay
- Test video playback (URL source) on both platforms
- Test video playback (WebTorrent) on both platforms
- Test service worker behavior in native WebViews
- Set iOS default to URL-first playback if WebTorrent is unreliable
Phase 3 — Desktop
- Configure Electron window defaults (size, min size, position memory)
- Set up native menu bar or hide it
- Register
nostr:protocol handler at OS level - Configure packaging (NSIS/DMG/AppImage)
- Test on Windows, macOS, and Linux
- Set up auto-updater with GitHub Releases feed
Phase 4 — Platform Enhancements
- Implement native share sheet integration
- Add
@capacitor/keyboardfor mobile input handling - Explore picture-in-picture on each platform
- Add haptic feedback for zap actions (optional)
- Implement app shell caching in service worker for offline support
Phase 5 — CI/CD
- Create
ci-android.ymlworkflow - Create
ci-ios.ymlworkflow - Create
ci-desktop.ymlworkflow (3-OS matrix) - Add path filters to limit when native CI runs
- Set up artifact uploads for debug builds
- Configure caching (Gradle, CocoaPods, node_modules)
- Add concurrency groups to cancel stale runs
- Document release signing process (keystores, certificates, notarization)
Phase 6 — Testing
- Add mobile viewport projects to Playwright config
- Create platform smoke test suite (
tests/native/) - Set up Android emulator tests in CI
- Set up iOS simulator tests in CI
- Test WebTorrent streaming in native WebViews on real devices
- Test service worker behavior across platforms
- Test deep link handling on all platforms
- Create cross-platform feature parity test matrix
- Document known platform-specific limitations in
KNOWN_ISSUES.md
App Store Submission
- Create Google Play developer account
- Prepare Play Store listing (screenshots, description, content rating)
- Submit Android app for review
- Create Apple Developer account (if not existing)
- Prepare App Store listing (screenshots, description, review notes)
- Submit iOS app for review
- Set up GitHub Releases for desktop distribution
- Notarize macOS DMG
Related Documentation
- Playback Fallback Architecture — URL-first strategy that mitigates WebTorrent issues on mobile
- Instance Configuration — Platform-specific config overrides
- WebTorrent Architecture — Service worker streaming details
- Moderation Service Overview — Content moderation (relevant for app store review)