diff --git a/ios/App/App.xcodeproj/project.pbxproj b/ios/App/App.xcodeproj/project.pbxproj index 7214d4a44c..121d2fe8b6 100644 --- a/ios/App/App.xcodeproj/project.pbxproj +++ b/ios/App/App.xcodeproj/project.pbxproj @@ -16,8 +16,6 @@ 50B271D11FEDC1A000F3C39B /* public in Resources */ = {isa = PBXBuildFile; fileRef = 50B271D01FEDC1A000F3C39B /* public */; }; 97EF2DC6FD76C3643D680B8D /* Pods_App.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 90DCAFB4D8948F7A50C13800 /* Pods_App.framework */; }; C86585DF2ED456DE00824752 /* TimeSafariShareExtension.appex in Embed Foundation Extensions */ = {isa = PBXBuildFile; fileRef = C86585D52ED456DE00824752 /* TimeSafariShareExtension.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; }; - C86585E82ED45A3E00824752 /* ShareImageBridge.swift in Sources */ = {isa = PBXBuildFile; fileRef = C86585E72ED45A3D00824752 /* ShareImageBridge.swift */; }; - C8D7E2CC2ED46A3B00DD738D /* ShareImagePlugin.swift in Sources */ = {isa = PBXBuildFile; fileRef = C8D7E2CB2ED46A3B00DD738D /* ShareImagePlugin.swift */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -57,8 +55,6 @@ 90DCAFB4D8948F7A50C13800 /* Pods_App.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_App.framework; sourceTree = BUILT_PRODUCTS_DIR; }; C86585D52ED456DE00824752 /* TimeSafariShareExtension.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = TimeSafariShareExtension.appex; sourceTree = BUILT_PRODUCTS_DIR; }; C86585E52ED4577F00824752 /* App.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = App.entitlements; sourceTree = ""; }; - C86585E72ED45A3D00824752 /* ShareImageBridge.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShareImageBridge.swift; sourceTree = ""; }; - C8D7E2CB2ED46A3B00DD738D /* ShareImagePlugin.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShareImagePlugin.swift; sourceTree = ""; }; E2E9297D5D02C549106C77F9 /* Pods-App.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-App.release.xcconfig"; path = "Target Support Files/Pods-App/Pods-App.release.xcconfig"; sourceTree = ""; }; EAEC6436E595F7CD3A1C9E96 /* Pods-App.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-App.debug.xcconfig"; path = "Target Support Files/Pods-App/Pods-App.debug.xcconfig"; sourceTree = ""; }; /* End PBXFileReference section */ @@ -127,8 +123,6 @@ 504EC3061FED79650016851F /* App */ = { isa = PBXGroup; children = ( - C8D7E2CB2ED46A3B00DD738D /* ShareImagePlugin.swift */, - C86585E72ED45A3D00824752 /* ShareImageBridge.swift */, C86585E52ED4577F00824752 /* App.entitlements */, 50379B222058CBB4000EE86E /* capacitor.config.json */, 504EC3071FED79650016851F /* AppDelegate.swift */, @@ -345,8 +339,6 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - C8D7E2CC2ED46A3B00DD738D /* ShareImagePlugin.swift in Sources */, - C86585E82ED45A3E00824752 /* ShareImageBridge.swift in Sources */, 504EC3081FED79650016851F /* AppDelegate.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; diff --git a/ios/App/App/ShareImageBridge.swift b/ios/App/App/ShareImageBridge.swift deleted file mode 100644 index 88ad874295..0000000000 --- a/ios/App/App/ShareImageBridge.swift +++ /dev/null @@ -1,48 +0,0 @@ -import Foundation - -/** - * Share Image Bridge - * - * Provides a bridge between JavaScript and native iOS code to access - * shared images stored in App Group UserDefaults by the Share Extension. - * - * This bridge allows the JavaScript layer to read shared image data - * that was stored by the Share Extension. - * - * Note: This class doesn't need Capacitor - it's a simple Swift utility - * that reads from App Group UserDefaults. The JavaScript bridge will be - * implemented separately. - */ -@objc(ShareImageBridge) -public class ShareImageBridge: NSObject { - - private static let appGroupIdentifier = "group.app.timesafari" - private static let sharedPhotoBase64Key = "sharedPhotoBase64" - private static let sharedPhotoFileNameKey = "sharedPhotoFileName" - - /** - * Get shared image data from App Group UserDefaults - * Called from JavaScript via Capacitor bridge - * - * @returns Dictionary with "base64" and "fileName" keys, or nil if no shared image - */ - @objc public static func getSharedImageData() -> [String: String]? { - guard let userDefaults = UserDefaults(suiteName: appGroupIdentifier) else { - print("ShareImageBridge: Failed to access App Group UserDefaults") - return nil - } - - guard let base64 = userDefaults.string(forKey: sharedPhotoBase64Key), - let fileName = userDefaults.string(forKey: sharedPhotoFileNameKey) else { - return nil - } - - // Clear the shared data after reading - userDefaults.removeObject(forKey: sharedPhotoBase64Key) - userDefaults.removeObject(forKey: sharedPhotoFileNameKey) - userDefaults.synchronize() - - return ["base64": base64, "fileName": fileName] - } -} - diff --git a/ios/App/App/ShareImagePlugin.swift b/ios/App/App/ShareImagePlugin.swift deleted file mode 100644 index 9073de7f6e..0000000000 --- a/ios/App/App/ShareImagePlugin.swift +++ /dev/null @@ -1,28 +0,0 @@ -import Foundation -import Capacitor - -/** - * Share Image Plugin - * - * Capacitor plugin that exposes ShareImageBridge functionality to JavaScript. - * Allows JavaScript to retrieve shared images from App Group UserDefaults. - */ -@objc(ShareImagePlugin) -public class ShareImagePlugin: CAPPlugin { - - @objc func getSharedImageData(_ call: CAPPluginCall) { - guard let sharedData = ShareImageBridge.getSharedImageData() else { - call.resolve(["success": false, "data": NSNull()]) - return - } - - call.resolve([ - "success": true, - "data": [ - "base64": sharedData["base64"] ?? "", - "fileName": sharedData["fileName"] ?? "" - ] - ]) - } -} - diff --git a/src/main.capacitor.ts b/src/main.capacitor.ts index 1bc7f08ef7..cd0cf71784 100644 --- a/src/main.capacitor.ts +++ b/src/main.capacitor.ts @@ -192,18 +192,17 @@ async function checkAndStoreNativeSharedImage(): Promise<{ `[Main] Checking for ${platform} shared image from native layer`, ); - // Use Capacitor's native bridge to call the ShareImagePlugin - // eslint-disable-next-line @typescript-eslint/no-explicit-any - const capacitor = (window as any).Capacitor; - - if (!capacitor || !capacitor.Plugins) { - logger.debug("[Main] Capacitor plugins not available"); - isProcessingSharedImage = false; - return { success: false }; - } - - // WORKAROUND: Since the plugin isn't being auto-discovered, use a temp file bridge - // Native layer (AppDelegate on iOS, MainActivity on Android) writes the shared image data to a temp file, and we read it here + // TEMP FILE APPROACH: + // Native layer (AppDelegate on iOS, MainActivity on Android) writes the shared image data + // to a temp file, and we read it here using Capacitor's Filesystem plugin. + // + // This approach is simple, reliable, and works consistently across both platforms. + // The temp file is deleted immediately after reading to prevent re-processing. + // + // FUTURE IMPROVEMENT: Consider implementing Capacitor plugins for iOS and Android + // to provide a more direct native-to-JS bridge. This would eliminate the need for + // file I/O and polling, providing lower latency and a more "native" integration. + // However, the current temp file approach is production-ready and performs well. const tempFilePath = "timesafari_shared_photo.json"; // Use platform-specific directory: @@ -250,96 +249,20 @@ async function checkAndStoreNativeSharedImage(): Promise<{ } } } catch (fileError: unknown) { - // File exists but can't be read - log and continue to plugin method - logger.debug( - "[Main] Temp file exists but couldn't be read, trying plugin method", + logger.error( + "[Main] Temp file exists but couldn't be read:", + fileError, ); - } - } else { - logger.debug( - "[Main] Temp file not found after polling (this is normal if plugin works)", - ); - } - - // NOTE: Plugin registration issue - ShareImage plugin is not being auto-discovered - // This is a known issue that needs to be resolved. For now, we use the temp file workaround above. - - // Try multiple methods to call the plugin (fallback if temp file method fails) - // eslint-disable-next-line @typescript-eslint/no-explicit-any - const plugins = (capacitor as any).Plugins; - // eslint-disable-next-line @typescript-eslint/no-explicit-any - const shareImagePlugin = (plugins as any)?.ShareImage; - - // eslint-disable-next-line @typescript-eslint/no-explicit-any - let result: any = null; - - if ( - shareImagePlugin && - typeof shareImagePlugin.getSharedImageData === "function" - ) { - logger.debug("[Main] Using direct plugin method"); - try { - result = await shareImagePlugin.getSharedImageData(); - } catch (pluginError) { - logger.error("[Main] Plugin call failed:", pluginError); isProcessingSharedImage = false; return { success: false }; } } else { - // Method 2: Use Capacitor's execute method - logger.debug( - "[Main] Plugin not found directly, trying Capacitor.execute", - ); - try { - // eslint-disable-next-line @typescript-eslint/no-explicit-any - const bridge = (capacitor as any).getBridge?.(); - if (bridge) { - // eslint-disable-next-line @typescript-eslint/no-explicit-any - result = await bridge.execute({ - pluginId: "ShareImage", - methodName: "getSharedImageData", - options: {}, - }); - } else { - // Method 3: Try execute on Plugins object - // eslint-disable-next-line @typescript-eslint/no-explicit-any - if ((plugins as any)?.execute) { - // eslint-disable-next-line @typescript-eslint/no-explicit-any - result = await (plugins as any).execute( - "ShareImage", - "getSharedImageData", - {}, - ); - } - } - } catch (executeError) { - logger.error("[Main] Execute method failed:", executeError); - isProcessingSharedImage = false; - return { success: false }; - } + logger.debug("[Main] Temp file not found after polling"); } - if (!result || !result.success || !result.data) { - logger.debug("[Main] No shared image data found in result"); - isProcessingSharedImage = false; - return { success: false }; - } - - const { base64, fileName } = result.data; - - if (!base64) { - logger.debug("[Main] Shared image data missing base64"); - isProcessingSharedImage = false; - return { success: false }; - } - - logger.info("[Main] Native shared image found, storing in temp DB"); - - // Store in temp database using extracted method - await storeSharedImageInTempDB(base64, fileName); - + // No shared image found isProcessingSharedImage = false; - return { success: true, fileName: fileName || "shared-image.jpg" }; + return { success: false }; } catch (error) { logger.error("[Main] Error checking for native shared image:", error); isProcessingSharedImage = false;