Files
crowd-funder-from-jason/doc/ios-share-extension-setup.md
Jose Olarte III ae49c0e907 feat(ios): implement native share target for images
Implement iOS Share Extension to enable native image sharing from Photos
and other apps directly into TimeSafari. Users can now share images from
the iOS share sheet, which will open in SharedPhotoView for use as gifts
or profile pictures.

iOS Native Implementation:
- Add TimeSafariShareExtension target with ShareViewController
- Configure App Groups for data sharing between extension and main app
- Implement ShareViewController to process shared images and convert to base64
- Store shared image data in App Group UserDefaults
- Add ShareImageBridge utility to read shared data from App Group
- Update AppDelegate to handle shared-photo deep link and bridge data to JS

JavaScript Integration:
- Add checkAndStoreNativeSharedImage() in main.capacitor.ts to read shared
  images from native layer via temporary file bridge
- Convert base64 data to data URL format for compatibility with base64ToBlob
- Integrate with existing SharedPhotoView component
- Add "shared-photo" to deep link validation schema

Build System:
- Integrate Xcode 26 / CocoaPods compatibility workaround into build-ios.sh
- Add run_pod_install_with_workaround() for explicit pod install
- Add run_cap_sync_with_workaround() for Capacitor sync (which runs pod
  install internally)
- Automatically detect project format version 70 and apply workaround
- Remove standalone pod-install-workaround.sh script

Code Cleanup:
- Remove verbose debug logs from ShareViewController, AppDelegate, and
  main.capacitor.ts
- Retain essential logger calls for production debugging

Documentation:
- Add ios-share-extension-setup.md with manual Xcode setup instructions
- Add ios-share-extension-git-commit-guide.md for version control best practices
- Add ios-share-implementation-status.md tracking implementation progress
- Add native-share-target-implementation.md with overall architecture
- Add xcode-26-cocoapods-workaround.md documenting the compatibility issue

The implementation uses a temporary file bridge (AppDelegate writes to Documents
directory, JS reads via Capacitor Filesystem plugin) as a workaround for
Capacitor plugin auto-discovery issues. This can be improved in the future by
properly registering ShareImagePlugin in Capacitor's plugin registry.
2025-11-24 20:46:58 +08:00

4.8 KiB

iOS Share Extension Setup Instructions

Date: 2025-01-27
Purpose: Step-by-step instructions for setting up the iOS Share Extension in Xcode

Prerequisites

  • Xcode installed
  • iOS project already set up with Capacitor
  • Access to Apple Developer account (for App Groups)

Step 1: Create Share Extension Target

  1. Open ios/App/App.xcodeproj in Xcode
  2. In the Project Navigator, select the App project (top-level item)
  3. Click the + button at the bottom of the Targets list
  4. Select iOSShare Extension
  5. Click Next
  6. Configure:
    • Product Name: TimeSafariShareExtension
    • Bundle Identifier: app.timesafari.shareextension (must match main app's bundle ID with .shareextension suffix)
    • Language: Swift
  7. Click Finish

Step 2: Configure Share Extension Files

The following files have been created in ios/App/TimeSafariShareExtension/:

  • ShareViewController.swift - Main extension logic
  • Info.plist - Extension configuration

Verify these files exist and are added to the Share Extension target.

Step 3: Configure App Groups

App Groups allow the Share Extension and main app to share data.

For Main App Target:

  1. Select the App target in Xcode
  2. Go to Signing & Capabilities tab
  3. Click + Capability
  4. Select App Groups
  5. Click + to add a new group
  6. Enter: group.app.timesafari
  7. Ensure it's checked/enabled

For Share Extension Target:

  1. Select the TimeSafariShareExtension target
  2. Go to Signing & Capabilities tab
  3. Click + Capability
  4. Select App Groups
  5. Click + to add a new group
  6. Enter: group.app.timesafari (same as main app)
  7. Ensure it's checked/enabled

Important: Both targets must use the exact same App Group identifier.

Step 4: Configure Share Extension Info.plist

The Info.plist file should already be configured, but verify:

  1. Select TimeSafariShareExtension/Info.plist in Xcode
  2. Ensure it contains:
    • NSExtensionPointIdentifier = com.apple.share-services
    • NSExtensionPrincipalClass = $(PRODUCT_MODULE_NAME).ShareViewController
    • NSExtensionActivationSupportsImageWithMaxCount = 1

Step 5: Add ShareImageBridge to Main App

  1. The file ios/App/App/ShareImageBridge.swift has been created
  2. Ensure it's added to the App target (not the Share Extension target)
  3. In Xcode, select the file and check the Target Membership in the File Inspector

Step 6: Build and Test

  1. Select the App scheme (not the Share Extension scheme)
  2. Build and run on a device or simulator
  3. Open Photos app
  4. Select an image
  5. Tap Share button
  6. Look for TimeSafari Share in the share sheet
  7. Select it
  8. The app should open and navigate to the shared photo view

Step 7: Troubleshooting

Share Extension doesn't appear in share sheet

  • Verify the Share Extension target builds successfully
  • Check that Info.plist is correctly configured
  • Ensure the extension's bundle identifier follows the pattern: {main-app-bundle-id}.shareextension
  • Clean build folder (Product → Clean Build Folder)

App Group access fails

  • Verify both targets have the same App Group identifier
  • Check that App Groups capability is enabled for both targets
  • Ensure you're signed in with a valid Apple Developer account
  • For development, you may need to enable App Groups in your Apple Developer account

Shared image not appearing

  • Check Xcode console for errors
  • Verify ShareViewController.swift is correctly implemented
  • Ensure the deep link timesafari://shared-photo is being handled
  • Check that the native bridge method is being called

Build errors

  • Ensure Swift version matches between targets
  • Check that all required frameworks are linked
  • Verify deployment targets match between main app and extension

Step 8: Native Bridge Implementation (TODO)

Currently, the JavaScript code needs a way to call the native getSharedImageData() method. This requires one of:

  1. Option A: Create a minimal Capacitor plugin
  2. Option B: Use Capacitor's existing bridge mechanisms
  3. Option C: Expose the method via a custom URL scheme parameter

The current implementation in main.capacitor.ts has a placeholder that needs to be completed.

Next Steps

After the Share Extension is set up and working:

  1. Complete the native bridge implementation to read from App Group
  2. Test end-to-end flow: Share image → Extension stores → App reads → Displays
  3. Implement Android version
  4. Add error handling and edge cases

References