# Shared Image Plugin - Pre-Implementation Decision Checklist **Date:** 2025-12-03 **Status:** Pre-Implementation Planning **Purpose:** Identify and document decisions needed before implementing SharedImagePlugin ## ✅ Completed Decisions ### 1. Minimum OS Versions - ✅ **iOS**: Keep at 13.0 (no changes needed) - ✅ **Android**: Upgraded from API 22 to API 23 (completed) - ✅ **Rationale**: Meets Capacitor 6 requirements, minimal device impact ### 2. Data Storage Strategy - ✅ **iOS**: Use App Group UserDefaults (already implemented in Share Extension) - ✅ **Android**: Use SharedPreferences (to be implemented) - ✅ **Rationale**: Direct, efficient, no file I/O needed ## 🔍 Decisions Needed Before Implementation ### 1. Plugin Method Design #### Decision: What methods should the plugin expose? **Options:** - **Option A (Minimal)**: Only `getSharedImage()` - read and clear in one call - **Option B (Recommended)**: `getSharedImage()` + `hasSharedImage()` - allows checking without reading - **Option C (Extended)**: Add `clearSharedImage()` - explicit clearing without reading **Recommendation:** **Option B** - `getSharedImage()`: Returns `{ base64: string, fileName: string } | null` - `hasSharedImage()`: Returns `{ hasImage: boolean }` - useful for quick checks **Decision Needed:** ✅ Confirm Option B or choose alternative --- ### 2. Error Handling Strategy #### Decision: How should the plugin handle errors? **Options:** - **Option A**: Return `null` for all errors (no shared image = no error) - **Option B**: Use `call.reject()` for actual errors, return `null` only when no image exists - **Option C**: Return error object in result: `{ error: string } | { base64: string, fileName: string }` **Recommendation:** **Option B** - `getSharedImage()` returns `null` when no image exists (normal case) - `call.reject()` for actual errors (UserDefaults unavailable, data corruption, etc.) - Clear distinction between "no data" (normal) vs "error" (exceptional) **Decision Needed:** ✅ Confirm Option B or choose alternative --- ### 3. Data Clearing Strategy #### Decision: When should shared image data be cleared? **Current Behavior (temp file approach):** - Data cleared after reading (immediate) **Options:** - **Option A**: Clear immediately after reading (current behavior) - **Option B**: Clear on next read (allow re-reading until consumed) - **Option C**: Clear after successful storage in temp DB (JS confirms receipt) **Recommendation:** **Option A** (immediate clearing) - Prevents accidental re-reading - Simpler implementation - Matches current behavior - If JS fails to store, user can share again **Decision Needed:** ✅ Confirm Option A or choose alternative --- ### 4. iOS Plugin Registration #### Decision: How should the iOS plugin be registered? **Options:** - **Option A**: Auto-discovery (Capacitor finds plugins by naming convention) - **Option B**: Manual registration in AppDelegate - **Option C**: Hybrid (auto-discovery with manual registration as fallback) **Recommendation:** **Option A** (auto-discovery) - Follows Capacitor best practices - Less code to maintain - Other plugins in project use auto-discovery (SafeAreaPlugin uses manual, but that's older pattern) **Note:** Need to verify plugin naming convention: - Class name: `SharedImagePlugin` - File name: `SharedImagePlugin.swift` - Location: `ios/App/App/SharedImagePlugin.swift` **Decision Needed:** ✅ Confirm Option A, or if auto-discovery doesn't work, use Option B --- ### 5. TypeScript Interface Design #### Decision: What should the TypeScript interface look like? **Proposed Interface:** ```typescript export interface SharedImageResult { base64: string; fileName: string; } export interface SharedImagePlugin { getSharedImage(): Promise; hasSharedImage(): Promise<{ hasImage: boolean }>; } ``` **Questions:** - Should `fileName` be optional? (Currently always provided, but could be empty string) - Should we include metadata (image size, MIME type)? - Should `hasSharedImage()` return more info (like fileName without reading)? **Recommendation:** Keep simple for now: - `fileName` is always a string (may be default "shared-image.jpg") - No metadata initially (can add later if needed) - `hasSharedImage()` only returns boolean (keep it lightweight) **Decision Needed:** ✅ Confirm interface design or request changes --- ### 6. Android Data Storage Timing #### Decision: When should Android store shared image data in SharedPreferences? **Current Flow:** 1. Share intent received in MainActivity 2. Image processed and written to temp file 3. JS reads temp file **New Flow Options:** - **Option A**: Store in SharedPreferences immediately when share intent received (in `processSharedImage()`) - **Option B**: Store when plugin is first called (lazy loading) - **Option C**: Store in both places during transition (backward compatibility) **Recommendation:** **Option A** (immediate storage) - Data available immediately when plugin is called - No timing issues - Matches iOS pattern (data stored by Share Extension) **Implementation:** - Update `processSharedImage()` in MainActivity to store in SharedPreferences - Remove temp file writing - Plugin reads from SharedPreferences **Decision Needed:** ✅ Confirm Option A --- ### 7. Migration Strategy #### Decision: How to handle the transition from temp file to plugin? **Options:** - **Option A (Clean Break)**: Remove temp file code immediately, use plugin only - **Option B (Gradual)**: Support both approaches temporarily, remove temp file later - **Option C (Feature Flag)**: Use feature flag to switch between approaches **Recommendation:** **Option A** (clean break) - Simpler implementation - Less code to maintain - Temp file approach is buggy anyway (why we're replacing it) - Can rollback via git if needed **Rollback Plan:** - Keep temp file code in git history - If plugin has issues, can revert commit - Test thoroughly before removing temp file code **Decision Needed:** ✅ Confirm Option A --- ### 8. Plugin Naming #### Decision: What should the plugin be named? **Options:** - **Option A**: `SharedImage` (matches file/class names) - **Option B**: `SharedImagePlugin` (more explicit) - **Option C**: `NativeShare` (more generic, could handle other share types) **Recommendation:** **Option A** (`SharedImage`) - Matches Capacitor naming conventions (plugins are referenced without "Plugin" suffix) - Examples: `Capacitor.Plugins.Camera`, `Capacitor.Plugins.Filesystem` - TypeScript: `SharedImage.getSharedImage()` **Decision Needed:** ✅ Confirm Option A --- ### 9. iOS: Reuse getSharedImageData() or Move to Plugin? #### Decision: Should the plugin reuse AppDelegate's `getSharedImageData()` or implement its own? **Current Code:** - `AppDelegate.getSharedImageData()` exists and works - Reads from App Group UserDefaults - Clears data after reading **Options:** - **Option A**: Plugin calls `getSharedImageData()` from AppDelegate - **Option B**: Plugin implements its own logic (duplicate code) - **Option C**: Move `getSharedImageData()` to a shared utility, both use it **Recommendation:** **Option C** (shared utility) - DRY principle - Single source of truth - But: May be overkill for simple logic **Alternative Recommendation:** **Option B** (plugin implements own logic) - Plugin is self-contained - No dependency on AppDelegate - Logic is simple (just UserDefaults read/clear) - Can remove `getSharedImageData()` from AppDelegate after migration **Decision:** ✅ **Option C** (shared utility) - **CONFIRMED** - Create shared utility for reading from App Group UserDefaults - Both AppDelegate and plugin use the shared utility - Single source of truth for shared image data access --- ### 10. Android: SharedPreferences Key Names #### Decision: What keys should be used in SharedPreferences? **Proposed Keys:** - `shared_image_base64` - Base64 string - `shared_image_file_name` - File name - `shared_image_ready` - Boolean flag (optional, for quick checks) **Alternative:** - Use a single JSON object: `shared_image_data` = `{ base64: "...", fileName: "..." }` **Recommendation:** Separate keys (first option) - Simpler to read/write - No JSON parsing needed - Matches iOS pattern (separate UserDefaults keys) - Flag is optional but useful for `hasSharedImage()` **Decision Needed:** ✅ Confirm key naming or request changes --- ### 11. Testing Strategy #### Decision: What testing approach should we use? **Options:** - **Option A**: Manual testing only - **Option B**: Manual + automated unit tests for plugin methods - **Option C**: Manual + integration tests **Recommendation:** **Option A** (manual testing) for now - Plugins are hard to unit test (require native environment) - Manual testing is sufficient for initial implementation - Can add automated tests later if needed **Test Scenarios:** 1. Share image from Photos app → Verify appears in app 2. Share while app backgrounded → Verify appears when app becomes active 3. Share while app closed → Verify appears on app launch 4. Multiple rapid shares → Verify only latest is processed 5. Share then close app before processing → Verify data persists 6. Share then clear app data → Verify graceful handling **Decision Needed:** ✅ Confirm testing approach --- ### 12. Documentation Updates #### Decision: What documentation needs updating? **Files to Update:** - ✅ Implementation plan (this document) - ⚠️ `doc/native-share-target-implementation.md` - Update to reflect plugin approach - ⚠️ `doc/ios-share-implementation-status.md` - Mark plugin as implemented - ⚠️ Code comments in `main.capacitor.ts` - Update to reflect plugin usage **Decision Needed:** ✅ Confirm documentation update list --- ## Summary of Decisions Needed | # | Decision | Recommendation | Status | |---|----------|----------------|--------| | 1 | Plugin Methods | Option B: `getSharedImage()` + `hasSharedImage()` | ✅ Confirmed | | 2 | Error Handling | Option B: `null` for no data, `reject()` for errors | ✅ Confirmed | | 3 | Data Clearing | Option A: Clear immediately after reading | ✅ Confirmed | | 4 | iOS Registration | Option A: Auto-discovery | ✅ Confirmed | | 5 | TypeScript Interface | Proposed interface (see above) | ✅ Confirmed | | 6 | Android Storage Timing | Option A: Store immediately on share intent | ✅ Confirmed | | 7 | Migration Strategy | Option A: Clean break, remove temp file code | ✅ Confirmed | | 8 | Plugin Naming | Option A: `SharedImage` | ✅ Confirmed | | 9 | iOS Code Reuse | Option C: Shared utility | ✅ Confirmed | | 10 | Android Key Names | Separate keys: `shared_image_base64`, `shared_image_file_name` | ✅ Confirmed | | 11 | Testing Strategy | Option A: Manual testing | ✅ Confirmed | | 12 | Documentation | Update listed files | ✅ Confirmed | | - | Multiple Images | Single image only (SharedPhotoView requirement) | ✅ Confirmed | | - | Backward Compatibility | No temp file backward compatibility | ✅ Confirmed | ## Next Steps 1. **Review this checklist** and confirm or modify recommendations 2. **Make decisions** on all pending items 3. **Update implementation plan** with confirmed decisions 4. **Begin implementation** with clear specifications ## Questions to Consider - Are there any edge cases not covered? - Should we support multiple images (currently only first image)? - Should we add image metadata (size, MIME type) in the future? - Do we need backward compatibility with temp file approach? - Should plugin methods be synchronous or async? (Capacitor plugins are async by default)