Files
crowd-funder-for-time-pwa/doc/share-target-ios-audit.md
Jose Olarte III a3e9a0104d feat(ios): expose shareId from getSharedImage()
Include the existing native sharedPhotoShareId in the SharedImage
getSharedImage() result so the web layer can identify the current share.
Add shareId to the native result dictionary and plugin response (NSNull on
the no-image branch), and add shareId: string to the TypeScript
SharedImageResult interface.

This surfaces a value that was already produced natively (previously used
only for logging) so application code can later pass it to markProcessed().
No behavior changes beyond exposing the value; Android untouched. Updates
doc/share-target-ios-audit.md accordingly.
2026-06-30 11:02:59 +08:00

3.8 KiB

iOS Share Target Audit

Date: 2026-06-30 Platform: iOS only (Android unchanged) Status: Phase 1D complete — explicit share completion API added (not yet called)

Purpose

This document tracks the native iOS share-target lifecycle and the Capacitor API surface exposed to the web/TypeScript layer. It is updated as each phase lands.

Lifecycle Overview

  1. The Share Extension (ShareViewController.swift) receives an image, writes it to the App Group container, records metadata in App Group UserDefaults, assigns a shareId (UUID), sets the sharedPhotoReady flag, and opens the main app via timesafari://.
  2. The main app reads the shared image through the SharedImage Capacitor plugin.
  3. The application layer processes the image, then (in a future phase) signals explicit completion via markProcessed(shareId).

App Group Storage Keys

Stored in UserDefaults(suiteName: "group.app.trentlarson.timesafari.share"):

Key Set by Meaning
sharedPhotoFileName Share Extension Original display filename
sharedPhotoFilePath Share Extension On-disk filename in App Group container
sharedPhotoShareId Share Extension Current pending share identifier (UUID)
sharedPhotoReady Share Extension Flag indicating a share is ready
sharedPhotoProcessedShareId Main app (markProcessed) Last shareId explicitly marked processed (Phase 1D)

Capacitor API (SharedImage plugin)

The plugin is registered as SharedImage and is implemented in:

  • Native iOS: ios/App/App/SharedImagePlugin.swift (delegates to ios/App/App/SharedImageUtility.swift)
  • Web stub: src/plugins/SharedImagePlugin.web.ts
  • TypeScript definitions: src/plugins/definitions.ts

getSharedImage(): Promise<SharedImageResult | null>

Returns the shared image as { base64, fileName, shareId }, or null if none exists. shareId is the native sharedPhotoShareId (UUID assigned by the Share Extension); pass it to markProcessed() to signal explicit completion. Read-only: native metadata and the file are left intact after retrieval (Phase 1C).

Note: On iOS the "no shared image" case resolves an object with base64, fileName, and shareId set to null; on web getSharedImage() resolves null directly.

hasSharedImage(): Promise<{ hasImage: boolean }>

Returns whether a shared image file currently exists, without reading it.

markProcessed(options: { shareId: string }): Promise<{ success: boolean }> — Phase 1D

Explicit completion signal from the application layer for a given share.

  • Input: shareId — the identifier reported by getSharedImage(). Must be a non-empty string; otherwise the call rejects.
  • Behavior (iOS): Records shareId in App Group UserDefaults under sharedPhotoProcessedShareId and resolves with { success: true }.
  • Does NOT delete files: The stored image file and share metadata are intentionally left intact. File cleanup is deferred to a later phase.
  • Web: No-op; resolves with { success: false }.
  • Logging: Emits [ShareTarget] shareId=<id> marked processed on success.

Note (Phase 1D): markProcessed is implemented and exposed to TypeScript but is not yet called from application code. Wiring it into the processing flow is a later phase.

Native Logging Reference

Relevant [ShareTarget] log lines emitted on iOS:

  • [ShareTarget] shareId=<id> retrieved
  • [ShareTarget] shareId=<id> left intact after retrieval
  • [ShareTarget] shareId=<id> marked processed (Phase 1D)

Out of Scope

  • Android: no changes. The Android plugin (android/app/src/main/java/app/timesafari/sharedimage/SharedImagePlugin.java) does not implement markProcessed.
  • File deletion / cleanup of processed shares.
  • Calling markProcessed from application code.