feat(share): "Biz Connect" in the iOS share sheet — share a photo/file into a chat

Adds the reverse direction: share FROM Photos/Files/Safari INTO a Biz Connect
conversation. An app can only appear in the iOS share sheet as an app-extension
target, so this is real native work, not a web change.

Pieces:
- mobile/ios-share/ShareViewController.swift: a UI-less Share Extension. It stages
  the shared items into the App Group container and opens bizconnect://share. It
  deliberately does NOT reimplement the chat picker — that lives in the app, which
  already has the chat list, search and upload progress. Appends to the manifest
  (never overwrites), so sharing twice before opening the app loses nothing.
- mobile/scripts/add-share-extension.rb: injects the extension target into the
  Capacitor-generated Xcode project on every CI build (Codemagic checks out fresh),
  using the xcodeproj gem that ships with CocoaPods. Embeds it, sets the bundle id
  <app>.share, and MERGES the App Group into the app's entitlements rather than
  clobbering them (push's aps-environment must survive). Idempotent.
- mobile/plugins/share-inbox: getPending()/clear() to read that manifest — the App
  Group container isn't one of Filesystem's known directories, so it needs a bridge.
- home.html: on bizconnect://share (and every resume, and cold-launch), read the
  inbox and show a "Send to…" picker over the chat list; chosen files run the SAME
  upload + /api/messages send as an in-app attachment. Reuses convertFileSrc to read
  the staged bytes with no base64 marshalling.
- ios-patch.sh registers the bizconnect URL scheme; codemagic.yaml fetches a profile
  for the .share bundle id too.

One-time manual gate (CI cannot toggle App capabilities): the App Group
group.com.bizgaze.connect must be created and enabled on both App IDs in the Apple
portal — documented in mobile/IOS_SETUP.md. Without it the two processes can't see
each other's files and sharing silently no-ops; everything else still works.

Validated cross-file: pod-name/jsName/method wiring for all three plugins, App
Group id identical in all 4 files, URL scheme consistent across extension/plist/web,
entitlement-merge preserves push. Needs a new iOS build (new targets + plugins).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-07-23 22:58:08 +05:30
parent 00ea140280
commit 0a2c7376b9
13 changed files with 632 additions and 1 deletions
+11
View File
@@ -40,6 +40,17 @@ set_bool() { "$PB" -c "Add :$1 bool $2" "$PLIST" 2>/dev/null || "$PB" -c "Set :$
set_bool UIFileSharingEnabled true
set_bool LSSupportsOpeningDocumentsInPlace true
# ── Custom URL scheme so the Share Extension can bounce the user back into the app ──────────────────
# The extension stages the shared files into the App Group, then opens bizconnect://share; the app reads
# the staged files and shows "Send to…". Registering the scheme is what makes that openURL succeed.
if ! "$PB" -c "Print :CFBundleURLTypes" "$PLIST" >/dev/null 2>&1; then
"$PB" -c "Add :CFBundleURLTypes array" "$PLIST"
"$PB" -c "Add :CFBundleURLTypes:0 dict" "$PLIST"
"$PB" -c "Add :CFBundleURLTypes:0:CFBundleURLName string com.bizgaze.connect" "$PLIST"
"$PB" -c "Add :CFBundleURLTypes:0:CFBundleURLSchemes array" "$PLIST"
"$PB" -c "Add :CFBundleURLTypes:0:CFBundleURLSchemes:0 string bizconnect" "$PLIST"
fi
# We use only standard encryption (HTTPS/TLS), which is exempt — declaring this up front stops App Store
# Connect from asking the "export compliance" question on every single build/TestFlight upload.
"$PB" -c "Add :ITSAppUsesNonExemptEncryption bool false" "$PLIST" 2>/dev/null \