anydrop/docs/ios-setup.md
ordinarthur 9674b19590
All checks were successful
Build & Deploy / build-and-deploy (push) Successful in 1m14s
feat(ios): Capacitor shell + Share Extension scaffold
Phase 4 (mobile) kickoff. Ships the native iOS wrapper that lets users
share photos/videos from the iOS Share Sheet into AnyDrop — the one
thing the PWA alone cannot do on iOS because Apple still ignores the
Web Share Target API.

Architecture:
- web/ios/ — Capacitor-generated Xcode project pointing the WKWebView
  at https://anydrop.arthurbarre.fr (real web app; only native code
  is the share-in path, so no "thin wrapper" App Store concern).
- AnyDropShare (Share Extension target) — stashes selected items into
  an App Group shared container then opens anydrop://share.
- SharedInboxPlugin (custom Capacitor plugin) — drains that container
  from JS after the URL fires, returning base64 blobs.
- web/src/lib/nativeShare.ts — bridge that rehydrates File objects and
  routes them into the existing /share page flow (same one Android uses).

Xcode-side target registration + signing isn't scriptable; runbook is
in docs/ios-setup.md.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-20 15:59:51 +02:00

3.5 KiB

iOS app setup — Xcode steps

The Capacitor shell + Share Extension code are committed. Xcode can't auto-register a new target from disk, so one-time Xcode work is needed before the first build.

1. Open the workspace

cd web
pnpm exec cap sync ios
pnpm exec cap open ios

cap sync copies the latest web build into ios/App/App/public and refreshes config. cap open launches Xcode on ios/App/App.xcworkspace.

2. Configure signing on the App target

  • Click the App project → App target → Signing & Capabilities.
  • Team: your Apple Developer team.
  • Bundle identifier: fr.arthurbarre.anydrop.
  • Add capability: App Groups → create group.fr.arthurbarre.anydrop.
  • Set the entitlements file to App/App.entitlements (already committed).

3. Add the Share Extension target

  • File → New → Target → iOS → Share Extension.
  • Product name: AnyDropShare.
  • Language: Swift.
  • Bundle identifier: fr.arthurbarre.anydrop.Share.
  • Delete the auto-generated files Xcode just created (ShareViewController.swift, MainInterface.storyboard, Info.plist).
  • In the Project navigator, right-click the AnyDropShare group → Add Files to "App"… → select the files already in ios/App/AnyDropShare/:
    • ShareViewController.swift
    • Info.plist
    • AnyDropShare.entitlements
  • With AnyDropShare target selected → Build Settings → search Info.plist File → set to AnyDropShare/Info.plist.
  • Build Settings → Code Signing Entitlements → set to AnyDropShare/AnyDropShare.entitlements.
  • Signing & Capabilities on the extension target:
    • Same team.
    • Add capability → App Groups → check group.fr.arthurbarre.anydrop (same as main app).
  • Also remove MainInterface.storyboard reference in the extension's Info.plist if Xcode re-added one — we use ShareViewController programmatically (NSExtensionPrincipalClass), no storyboard.

4. Build + run

  • Plug in an iPhone (Simulator also works but AirDrop/Messages targets aren't there).
  • Select the App scheme → pick your device → ⌘R.
  • First launch, iOS may ask to trust the developer certificate (Settings → General → VPN & Device Management).

5. Test the share flow

  1. Open Photos, select one or more images/videos, tap Share.
  2. Tap AnyDrop in the app row (scroll if needed — you can drag it to the front via "Edit Actions").
  3. Extension runs → writes files to the App Group → opens anydrop://share.
  4. Main app catches the URL → Capacitor fires appUrlOpen → JS drains the inbox → /share page shows the selected peer list → pick a device → P2P send.

6. Ship updates

  • Web changes (anything under web/src): the app loads from https://anydrop.arthurbarre.fr, so redeploying the web is enough. No App Store review needed.
  • Native changes (Swift, Info.plist, entitlements, Capacitor config): rebuild + re-archive + TestFlight or direct install.

Known gotchas

  • Custom URL scheme requires a real app install. Testing in Safari or the PWA will not fire appUrlOpen.
  • App Group must match exactly on both targets (group.fr.arthurbarre.anydrop). If they diverge, the extension writes and the app reads different directories.
  • Camera/photo permission prompt appears the first time the extension is used; the copy is in App/Info.plist (NSPhotoLibraryUsageDescription).
  • Cookies / sessions in Capacitor's WKWebView are not shared with Safari. Users will need to sign in inside the app once.