forked from trent_larson/crowd-funder-for-time-pwa
refactor(shared-image): replace temp file approach with native Capacitor plugins
Replace the buggy temp file polling mechanism with direct native-to-JS communication via custom Capacitor plugins for iOS and Android. This eliminates race conditions, file management complexity, and polling overhead. BREAKING CHANGE: Removes backward compatibility with temp file approach. Android minSdkVersion upgraded from 22 to 23. Changes: - iOS: Created SharedImagePlugin (CAPBridgedPlugin) and SharedImageUtility - Uses App Group UserDefaults for data sharing between extension and app - Implements getSharedImage() and hasSharedImage() methods - Removes temp file writing/reading logic from AppDelegate - Android: Created SharedImagePlugin with @CapacitorPlugin annotation - Uses SharedPreferences for data storage instead of temp files - Implements same interface as iOS plugin - Removes temp file handling from MainActivity - TypeScript: Added plugin definitions and registration - Created SharedImagePlugin interface and web fallback - Updated main.capacitor.ts to use plugin instead of Filesystem API - Removed pollForFileExistence() and related file I/O code - Android: Upgraded minSdkVersion from 22 to 23 - Required for SharedPreferences improvements and better API support Benefits: - Eliminates race conditions from file polling - Removes file cleanup complexity - Direct native-to-JS communication (no file I/O) - Better performance (no polling overhead) - More reliable data transfer between share extension and app - Cleaner architecture with proper plugin abstraction
This commit is contained in:
@@ -15,18 +15,20 @@ import android.webkit.WebSettings;
|
||||
import android.webkit.WebViewClient;
|
||||
import com.getcapacitor.BridgeActivity;
|
||||
import app.timesafari.safearea.SafeAreaPlugin;
|
||||
import app.timesafari.sharedimage.SharedImagePlugin;
|
||||
//import com.getcapacitor.community.sqlite.SQLite;
|
||||
|
||||
import android.content.SharedPreferences;
|
||||
import java.io.InputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileWriter;
|
||||
import java.io.IOException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
public class MainActivity extends BridgeActivity {
|
||||
private static final String TAG = "MainActivity";
|
||||
private static final String TEMP_FILE_NAME = "timesafari_shared_photo.json";
|
||||
private static final String SHARED_PREFS_NAME = "shared_image";
|
||||
private static final String KEY_BASE64 = "shared_image_base64";
|
||||
private static final String KEY_FILE_NAME = "shared_image_file_name";
|
||||
private static final String KEY_READY = "shared_image_ready";
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
@@ -62,6 +64,9 @@ public class MainActivity extends BridgeActivity {
|
||||
// Register SafeArea plugin
|
||||
registerPlugin(SafeAreaPlugin.class);
|
||||
|
||||
// Register SharedImage plugin
|
||||
registerPlugin(SharedImagePlugin.class);
|
||||
|
||||
// Initialize SQLite
|
||||
//registerPlugin(SQLite.class);
|
||||
|
||||
@@ -78,7 +83,7 @@ public class MainActivity extends BridgeActivity {
|
||||
|
||||
/**
|
||||
* Handle share intents (ACTION_SEND or ACTION_SEND_MULTIPLE)
|
||||
* Processes shared images and writes them to a temp file for JavaScript to read
|
||||
* Processes shared images and stores them in SharedPreferences for plugin to read
|
||||
*/
|
||||
private void handleShareIntent(Intent intent) {
|
||||
if (intent == null) {
|
||||
@@ -164,9 +169,8 @@ public class MainActivity extends BridgeActivity {
|
||||
}
|
||||
}
|
||||
|
||||
// Write to temp file in app's internal files directory
|
||||
// JavaScript will read this file using Capacitor's Filesystem plugin
|
||||
writeSharedImageToTempFile(base64String, actualFileName);
|
||||
// Store in SharedPreferences for plugin to read
|
||||
storeSharedImageInPreferences(base64String, actualFileName);
|
||||
|
||||
Log.d(TAG, "Successfully processed shared image: " + actualFileName);
|
||||
} catch (IOException e) {
|
||||
@@ -177,28 +181,21 @@ public class MainActivity extends BridgeActivity {
|
||||
}
|
||||
|
||||
/**
|
||||
* Write shared image data to temp JSON file for JavaScript to read
|
||||
* File is written to app's internal files directory (accessible via Capacitor Filesystem plugin)
|
||||
* Store shared image data in SharedPreferences for plugin to read
|
||||
* Plugin will read and clear the data when called
|
||||
*/
|
||||
private void writeSharedImageToTempFile(String base64, String fileName) {
|
||||
private void storeSharedImageInPreferences(String base64, String fileName) {
|
||||
try {
|
||||
// Get app's internal files directory
|
||||
File filesDir = getFilesDir();
|
||||
File tempFile = new File(filesDir, TEMP_FILE_NAME);
|
||||
SharedPreferences prefs = getSharedPreferences(SHARED_PREFS_NAME, MODE_PRIVATE);
|
||||
SharedPreferences.Editor editor = prefs.edit();
|
||||
editor.putString(KEY_BASE64, base64);
|
||||
editor.putString(KEY_FILE_NAME, fileName);
|
||||
editor.putBoolean(KEY_READY, true);
|
||||
editor.apply();
|
||||
|
||||
// Create JSON object
|
||||
JSONObject jsonData = new JSONObject();
|
||||
jsonData.put("base64", base64);
|
||||
jsonData.put("fileName", fileName);
|
||||
|
||||
// Write to file
|
||||
FileWriter writer = new FileWriter(tempFile);
|
||||
writer.write(jsonData.toString());
|
||||
writer.close();
|
||||
|
||||
Log.d(TAG, "Wrote shared image data to temp file: " + tempFile.getAbsolutePath());
|
||||
Log.d(TAG, "Stored shared image data in SharedPreferences");
|
||||
} catch (Exception e) {
|
||||
Log.e(TAG, "Error writing shared image to temp file", e);
|
||||
Log.e(TAG, "Error storing shared image in SharedPreferences", e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,79 @@
|
||||
package app.timesafari.sharedimage;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.SharedPreferences;
|
||||
import com.getcapacitor.JSObject;
|
||||
import com.getcapacitor.Plugin;
|
||||
import com.getcapacitor.PluginCall;
|
||||
import com.getcapacitor.PluginMethod;
|
||||
import com.getcapacitor.annotation.CapacitorPlugin;
|
||||
|
||||
@CapacitorPlugin(name = "SharedImage")
|
||||
public class SharedImagePlugin extends Plugin {
|
||||
|
||||
private static final String SHARED_PREFS_NAME = "shared_image";
|
||||
private static final String KEY_BASE64 = "shared_image_base64";
|
||||
private static final String KEY_FILE_NAME = "shared_image_file_name";
|
||||
private static final String KEY_READY = "shared_image_ready";
|
||||
|
||||
/**
|
||||
* Get shared image data from SharedPreferences
|
||||
* Returns base64 string and fileName, or null if no image exists
|
||||
* Clears the data after reading to prevent re-reading
|
||||
*/
|
||||
@PluginMethod
|
||||
public void getSharedImage(PluginCall call) {
|
||||
SharedPreferences prefs = getSharedPreferences();
|
||||
|
||||
String base64 = prefs.getString(KEY_BASE64, null);
|
||||
String fileName = prefs.getString(KEY_FILE_NAME, null);
|
||||
|
||||
if (base64 == null || fileName == null) {
|
||||
// No shared image exists - return null (not an error)
|
||||
JSObject result = new JSObject();
|
||||
result.put("base64", null);
|
||||
result.put("fileName", null);
|
||||
call.resolve(result);
|
||||
return;
|
||||
}
|
||||
|
||||
// Clear the shared data after reading
|
||||
SharedPreferences.Editor editor = prefs.edit();
|
||||
editor.remove(KEY_BASE64);
|
||||
editor.remove(KEY_FILE_NAME);
|
||||
editor.remove(KEY_READY);
|
||||
editor.apply();
|
||||
|
||||
// Return the shared image data
|
||||
JSObject result = new JSObject();
|
||||
result.put("base64", base64);
|
||||
result.put("fileName", fileName);
|
||||
call.resolve(result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if shared image exists without reading it
|
||||
* Useful for quick checks before calling getSharedImage()
|
||||
*/
|
||||
@PluginMethod
|
||||
public void hasSharedImage(PluginCall call) {
|
||||
SharedPreferences prefs = getSharedPreferences();
|
||||
boolean hasImage = prefs.contains(KEY_BASE64) && prefs.contains(KEY_FILE_NAME);
|
||||
|
||||
JSObject result = new JSObject();
|
||||
result.put("hasImage", hasImage);
|
||||
call.resolve(result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get SharedPreferences instance for shared image data
|
||||
*/
|
||||
private SharedPreferences getSharedPreferences() {
|
||||
Context context = getContext();
|
||||
if (context == null) {
|
||||
throw new IllegalStateException("Plugin context is null");
|
||||
}
|
||||
return context.getSharedPreferences(SHARED_PREFS_NAME, Context.MODE_PRIVATE);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user