Bluesky app fork with some witchin' additions 💫
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

at cope-settings-sync 134 lines 5.6 kB view raw view rendered
1# BlueskyClip 2 3An iOS App Clip implementation for Bluesky starter packs. App Clips are lightweight app experiences that allow users to preview and join Bluesky through starter packs without installing the full app. 4 5## What It Does 6 7BlueskyClip provides a minimal, on-demand iOS app experience for viewing and joining Bluesky starter packs. When a user encounters a starter pack link (e.g., `bsky.app/start/...` or `go.bsky.app/...`), iOS can present the App Clip instead of requiring a full app install. The App Clip: 8 91. Loads the starter pack web page in a WKWebView 102. Allows users to browse the starter pack content 113. Presents the App Store overlay when the user decides to join 124. Passes the starter pack URI to the main app via shared UserDefaults 13 14## Architecture 15 16### Native iOS Implementation 17 18The App Clip is a standalone iOS target with its own minimal Swift implementation: 19 20- **AppDelegate.swift**: Standard app delegate that sets up the view controller and handles URL routing (both direct URL opens and universal links) 21- **ViewController.swift**: Main view controller that manages the WKWebView, detects starter pack URLs, and communicates with the web layer 22 23### Communication Flow 24 25``` 26User taps starter pack link 27 28iOS presents BlueskyClip App Clip 29 30WKWebView loads bsky.app with ?clip=true parameter 31 32Web app detects clip mode and sends actions via postMessage 33 34ViewController receives messages and: 35 - Presents App Store overlay (action: "present") 36 - Stores starter pack URI in shared UserDefaults (action: "store") 37 38User downloads main app 39 40Main app reads starterPackUri from shared UserDefaults 41 42Main app displays starter pack onboarding flow 43``` 44 45### Key Implementation Details 46 47**URL Detection** (`isStarterPackUrl`): 48- Matches `bsky.app/start/*` and `bsky.app/starter-pack/*` paths (4 path components) 49- Matches short links `go.bsky.app/*` (2 path components) 50 51**WebView Communication** (`WKScriptMessageHandler`): 52- Listens for messages on the "onMessage" channel 53- Handles two action types: 54 - `present`: Shows the App Store overlay using `SKOverlay` 55 - `store`: Writes JSON data to shared UserDefaults with the specified key 56 57**Data Sharing**: 58- Uses UserDefaults suite `group.app.bsky` (App Group) 59- Primary key: `starterPackUri` - stores the starter pack URL 60- The main app reads this value on launch via `SharedPrefs.getString('starterPackUri')` (see `src/components/hooks/useStarterPackEntry.native.ts`) 61 62## Configuration 63 64### Build Configuration 65 66The App Clip target is automatically configured via Expo config plugins located in `/plugins/starterPackAppClipExtension/`: 67 68- **withStarterPackAppClip.js**: Main plugin that orchestrates all configuration 69- **withXcodeTarget.js**: Creates the App Clip target in Xcode with proper build settings 70- **withAppEntitlements.js**: Configures main app entitlements for App Clip association 71- **withClipEntitlements.js**: Sets up App Clip entitlements (App Groups, parent app identifier, associated domains) 72- **withClipInfoPlist.js**: Generates the Info.plist for the App Clip target 73- **withFiles.js**: Copies Swift source files and assets from `modules/BlueskyClip/` to the iOS build directory 74 75### Entitlements 76 77**Main App** (`app.entitlements`): 78- `com.apple.security.application-groups`: `group.app.bsky` 79- `com.apple.developer.associated-appclip-app-identifiers`: Links to the App Clip bundle ID 80 81**App Clip** (`BlueskyClip.entitlements`): 82- `com.apple.security.application-groups`: `group.app.bsky` (for data sharing) 83- `com.apple.developer.parent-application-identifiers`: Links to the main app bundle ID 84- `com.apple.developer.associated-domains`: Inherits from main app config (for universal links) 85 86### Build Settings 87 88- Deployment target: iOS 15.1+ 89- Bundle ID: `[main-app-bundle-id].AppClip` 90- Product type: `com.apple.product-type.application.on-demand-install-capable` 91- Development team: `B3LX46C5HS` 92- Device family: iPhone only (1) 93 94## Platform Support 95 96- **iOS**: Full support via native App Clip 97- **Android**: Not applicable (no App Clip equivalent) 98- **Web**: Not applicable (web uses standard starter pack landing pages) 99 100## Integration with Main App 101 102The main app detects App Clip-originated starter packs through `useStarterPackEntry` hook: 103 104**Native** (`src/components/hooks/useStarterPackEntry.native.ts`): 105- Reads `starterPackUri` from `SharedPrefs` (App Group) 106- Clears the value after reading to prevent re-use 107- Sets active starter pack in app state 108 109**Web** (`src/components/hooks/useStarterPackEntry.ts`): 110- Detects `?clip=true` URL parameter 111- Extracts starter pack URI from URL 112- Sets active starter pack with `isClip: true` flag 113 114## Files 115 116``` 117modules/BlueskyClip/ 118├── AppDelegate.swift # App lifecycle and URL handling 119├── ViewController.swift # WebView management and message handling 120└── Images.xcassets/ # App Clip icon assets 121 ├── AppIcon.appiconset/ 122 │ ├── App-Icon-1024x1024@1x.png 123 │ └── Contents.json 124 └── Contents.json 125``` 126 127## Development Notes 128 129- The App Clip is built as part of the main Xcode project when running `yarn prebuild` 130- Source files are copied during the prebuild process, not directly referenced 131- Changes to Swift files require running `yarn prebuild` to take effect 132- The App Clip shares the same version number as the main app 133- App Clips have a 15MB size limit (enforced by Apple) 134- Users can convert an App Clip session into a full app install without losing data (via shared App Group)