Files
crowd-funder-for-time-pwa/doc/share-target-ios-audit.md
Jose Olarte III 981f8b77d0 feat(ios): add markProcessed share-completion API (Phase 1D)
Add a native iOS markProcessed(shareId) method to the SharedImage plugin
that records an explicit completion signal in App Group UserDefaults
(sharedPhotoProcessedShareId) and logs "[ShareTarget] shareId=<id> marked
processed". The API is exposed to TypeScript via the plugin definitions and
a web no-op stub.

Deliberately does not delete files or clear share metadata (cleanup is
deferred to a later phase), is not yet called from application code, and
does not touch Android. Documents the share-target lifecycle and plugin API
in doc/share-target-ios-audit.md.
2026-06-30 11:00:52 +08:00

3.5 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 }, or null if none exists. Read-only: native metadata and the file are left intact after retrieval (Phase 1C).

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.