fix(android): resolve SharedPreferences mismatch and document cross-platform storage pattern
- Fix TestNativeFetcher to read from same SharedPreferences as plugin - Changed PREFS_NAME from 'DailyNotificationPrefs' to 'daily_notification_timesafari' - Changed KEY_STARRED_PLAN_IDS from 'starred_plan_ids' to 'starredPlanIds' - Updated getStarredPlanIds() to read from plugin's SharedPreferences location - Added diagnostic logging for plan ID loading - Add updateStarredPlans() call in App.vue mounted() hook - Ensures starred plan IDs are persisted to native storage on app startup - Allows native fetcher to read plan IDs from SharedPreferences - Added diagnostic logging for configuration flow - Document cross-platform storage pattern - Created docs/CROSS_PLATFORM_STORAGE_PATTERN.md with architecture flow - Documented TypeScript → Capacitor bridge → Plugin → Native storage → Native fetcher flow - Added iOS implementation checklist with code examples - Clarified why native storage is needed (background workers can't use bridge) - Add JWT generation logging to test-user-zero.ts - Log JWT algorithm (ES256K) and DID when token is generated - Helps diagnose JWT verification issues Fixes: - Empty planIds array in native fetcher requests - SharedPreferences key mismatch between plugin and native fetcher - Missing documentation for iOS implementation All changes maintain backward compatibility.
This commit is contained in:
@@ -50,9 +50,11 @@ public class TestNativeFetcher implements NativeNotificationContentFetcher {
|
||||
private static final int RETRY_DELAY_MS = 1000; // Base delay for exponential backoff
|
||||
|
||||
// SharedPreferences constants
|
||||
private static final String PREFS_NAME = "DailyNotificationPrefs";
|
||||
private static final String KEY_STARRED_PLAN_IDS = "starred_plan_ids";
|
||||
private static final String KEY_LAST_ACKED_JWT_ID = "last_acked_jwt_id";
|
||||
// NOTE: Must match plugin's SharedPreferences name and keys for starred plans
|
||||
// Plugin uses "daily_notification_timesafari" (see DailyNotificationPlugin.updateStarredPlans)
|
||||
private static final String PREFS_NAME = "daily_notification_timesafari";
|
||||
private static final String KEY_STARRED_PLAN_IDS = "starredPlanIds"; // Matches plugin key
|
||||
private static final String KEY_LAST_ACKED_JWT_ID = "last_acked_jwt_id"; // Plugin doesn't use this yet
|
||||
|
||||
private final Gson gson = new Gson();
|
||||
private final Context appContext;
|
||||
@@ -304,12 +306,17 @@ public class TestNativeFetcher implements NativeNotificationContentFetcher {
|
||||
*/
|
||||
private List<String> getStarredPlanIds() {
|
||||
try {
|
||||
String idsJson = prefs.getString(KEY_STARRED_PLAN_IDS, "[]");
|
||||
// Use the same SharedPreferences as the plugin (not the instance variable 'prefs')
|
||||
// Plugin stores in "daily_notification_timesafari" with key "starredPlanIds"
|
||||
SharedPreferences pluginPrefs = appContext.getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE);
|
||||
String idsJson = pluginPrefs.getString(KEY_STARRED_PLAN_IDS, "[]");
|
||||
|
||||
if (idsJson == null || idsJson.isEmpty() || idsJson.equals("[]")) {
|
||||
Log.d(TAG, "TestNativeFetcher: No starred plan IDs found in SharedPreferences");
|
||||
return new ArrayList<>();
|
||||
}
|
||||
|
||||
// Parse JSON array
|
||||
// Parse JSON array (plugin stores as JSON string)
|
||||
JsonParser parser = new JsonParser();
|
||||
JsonArray jsonArray = parser.parse(idsJson).getAsJsonArray();
|
||||
List<String> planIds = new ArrayList<>();
|
||||
@@ -318,11 +325,15 @@ public class TestNativeFetcher implements NativeNotificationContentFetcher {
|
||||
planIds.add(jsonArray.get(i).getAsString());
|
||||
}
|
||||
|
||||
Log.d(TAG, "TestNativeFetcher: Loaded " + planIds.size() + " starred plan IDs");
|
||||
Log.i(TAG, "TestNativeFetcher: Loaded " + planIds.size() + " starred plan IDs from SharedPreferences");
|
||||
if (planIds.size() > 0) {
|
||||
Log.d(TAG, "TestNativeFetcher: First plan ID: " +
|
||||
planIds.get(0).substring(0, Math.min(30, planIds.get(0).length())) + "...");
|
||||
}
|
||||
return planIds;
|
||||
|
||||
} catch (Exception e) {
|
||||
Log.e(TAG, "TestNativeFetcher: Error loading starred plan IDs", e);
|
||||
Log.e(TAG, "TestNativeFetcher: Error loading starred plan IDs from SharedPreferences", e);
|
||||
return new ArrayList<>();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -94,6 +94,20 @@ class App extends Vue {
|
||||
apiBaseUrl: apiBaseUrl.substring(0, 50) + '...',
|
||||
activeDid: TEST_USER_ZERO_CONFIG.identity.did.substring(0, 30) + '...'
|
||||
})
|
||||
|
||||
// Update starred plan IDs from config so native fetcher can use them
|
||||
console.log('🔧 App.vue: Updating starred plan IDs...')
|
||||
const planIds = [...TEST_USER_ZERO_CONFIG.starredProjects.planIds]
|
||||
console.log('🔧 App.vue: Plan IDs to update:', planIds.length, 'plans')
|
||||
|
||||
const updateResult = await DailyNotification.updateStarredPlans({
|
||||
planIds: planIds
|
||||
})
|
||||
|
||||
console.log('✅ App.vue: Starred plans updated:', {
|
||||
count: updateResult.planIdsCount,
|
||||
updatedAt: new Date(updateResult.updatedAt).toISOString()
|
||||
})
|
||||
} catch (error) {
|
||||
console.error('❌ App.vue: Failed to configure native fetcher:', error)
|
||||
console.error('❌ App.vue: Error details:', error instanceof Error ? error.stack : String(error))
|
||||
|
||||
@@ -267,6 +267,10 @@ export async function generateEndorserJWT(): Promise<string> {
|
||||
expiresIn: expiresIn
|
||||
});
|
||||
|
||||
const log = await getLogger();
|
||||
log.custom("🔐", "JWT generated - Algorithm: ES256K, DID:", TEST_USER_ZERO_CONFIG.identity.did.substring(0, 30) + "...");
|
||||
log.custom("🔐", "JWT length:", jwt.length, "characters");
|
||||
|
||||
return jwt;
|
||||
} catch (error) {
|
||||
const log = await getLogger();
|
||||
|
||||
Reference in New Issue
Block a user