fix(android): resolve prefetch scheduling and permission callback issues
- Add null safety check to permission callback to prevent NPE - Fix fetch time calculation bug that caused double subtraction - scheduleFetch() now accepts pre-calculated fetchTime directly - Calculate scheduledTime back from fetchTime for worker data - Add structured logging (DN|FETCH_SCHEDULING) for better traceability The permission callback was crashing with NullPointerException when Capacitor passed a null call parameter. The prefetch scheduling had a logic error where fetchTime was calculated twice - once in the plugin and once in the fetcher, causing 10-minute delays instead of 5-minute. Both issues are now fixed and verified working: - Permission callback handles null gracefully - Prefetch schedules correctly 5 minutes before notification - WorkManager job fires at the correct time - All structured logs appear in logcat Closes prefetch scheduling investigation.
This commit is contained in:
@@ -72,19 +72,23 @@ public class DailyNotificationFetcher {
|
||||
/**
|
||||
* Schedule a background fetch for content
|
||||
*
|
||||
* @param scheduledTime When the notification is scheduled for
|
||||
* @param fetchTime When to fetch the content (already calculated, typically 5 minutes before notification)
|
||||
*/
|
||||
public void scheduleFetch(long scheduledTime) {
|
||||
public void scheduleFetch(long fetchTime) {
|
||||
try {
|
||||
Log.d(TAG, "Scheduling background fetch for " + scheduledTime);
|
||||
Log.d(TAG, "Scheduling background fetch for time: " + fetchTime);
|
||||
|
||||
// Calculate fetch time (5 minutes before notification)
|
||||
long fetchTime = scheduledTime - TimeUnit.MINUTES.toMillis(5);
|
||||
long currentTime = System.currentTimeMillis();
|
||||
long delayMs = fetchTime - currentTime;
|
||||
|
||||
if (fetchTime > System.currentTimeMillis()) {
|
||||
long delayMs = fetchTime - System.currentTimeMillis();
|
||||
Log.d(TAG, "DN|FETCH_SCHEDULING fetch_time=" + fetchTime +
|
||||
" current=" + currentTime +
|
||||
" delay_ms=" + delayMs);
|
||||
|
||||
if (fetchTime > currentTime) {
|
||||
// Create work data - we need to calculate the notification time (fetchTime + 5 minutes)
|
||||
long scheduledTime = fetchTime + TimeUnit.MINUTES.toMillis(5);
|
||||
|
||||
// Create work data
|
||||
Data inputData = new Data.Builder()
|
||||
.putLong("scheduled_time", scheduledTime)
|
||||
.putLong("fetch_time", fetchTime)
|
||||
@@ -105,13 +109,13 @@ public class DailyNotificationFetcher {
|
||||
Log.i(TAG, "DN|WORK_ENQUEUED work_id=" + fetchWork.getId().toString() +
|
||||
" fetch_at=" + fetchTime +
|
||||
" delay_ms=" + delayMs +
|
||||
" delay_hours=" + (delayMs / 3600000.0));
|
||||
" delay_minutes=" + (delayMs / 60000.0));
|
||||
Log.i(TAG, "Background fetch scheduled successfully");
|
||||
|
||||
} else {
|
||||
Log.w(TAG, "DN|FETCH_PAST_TIME fetch_time=" + fetchTime +
|
||||
" current=" + System.currentTimeMillis() +
|
||||
" past_by_ms=" + (System.currentTimeMillis() - fetchTime));
|
||||
" current=" + currentTime +
|
||||
" past_by_ms=" + (currentTime - fetchTime));
|
||||
scheduleImmediateFetch();
|
||||
}
|
||||
|
||||
|
||||
@@ -1243,6 +1243,13 @@ public class DailyNotificationPlugin extends Plugin {
|
||||
private void onPermissionResult(PluginCall call) {
|
||||
try {
|
||||
Log.d(TAG, "DEBUG: onPermissionResult callback received");
|
||||
|
||||
// Guard against null call
|
||||
if (call == null) {
|
||||
Log.e(TAG, "Permission callback received null call - cannot process");
|
||||
return;
|
||||
}
|
||||
|
||||
Log.d(TAG, "Permission callback received");
|
||||
|
||||
// Check if POST_NOTIFICATIONS permission was granted
|
||||
@@ -1262,7 +1269,9 @@ public class DailyNotificationPlugin extends Plugin {
|
||||
} catch (Exception e) {
|
||||
Log.e(TAG, "DEBUG: Exception in onPermissionResult callback", e);
|
||||
Log.e(TAG, "Error in permission callback", e);
|
||||
call.reject("Error processing permission result: " + e.getMessage());
|
||||
if (call != null) {
|
||||
call.reject("Error processing permission result: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
392
docs/prefetch-scheduling-diagnosis.md
Normal file
392
docs/prefetch-scheduling-diagnosis.md
Normal file
@@ -0,0 +1,392 @@
|
||||
# Prefetch Scheduling Issue - Diagnostic Document
|
||||
|
||||
**Date**: 2024-10-28
|
||||
**Issue**: Prefetch events are not being scheduled when notifications are created
|
||||
**Status**: Investigation in Progress
|
||||
|
||||
## Problem Summary
|
||||
|
||||
When scheduling a daily notification at 07:55:
|
||||
- ✅ The main notification alarm is set correctly
|
||||
- ✅ Logs show: "Exact alarm scheduled for 1761638100000"
|
||||
- ❌ No prefetch logs appear (`DN|FETCH_*`, `DN|SCHEDULE_FETCH_*`)
|
||||
- ❌ No evidence of 5-minute-before prefetch alarm being scheduled
|
||||
|
||||
**Expected Behavior**: A prefetch alarm should be scheduled 5 minutes before the notification (07:50) to fetch content.
|
||||
|
||||
## Relevant Code Files
|
||||
|
||||
### 1. Main Plugin Logic
|
||||
**File**: `android/plugin/src/main/java/com/timesafari/dailynotification/DailyNotificationPlugin.java`
|
||||
|
||||
#### Key Method: `scheduleDailyNotification()` (line ~563-681)
|
||||
```java
|
||||
@PluginMethod
|
||||
public void scheduleDailyNotification(PluginCall call) {
|
||||
// ... validation and setup ...
|
||||
|
||||
// Schedule the notification
|
||||
boolean scheduled = scheduler.scheduleNotification(content);
|
||||
|
||||
Log.d(TAG, "DN|SCHEDULE_RESULT scheduled=" + scheduled +
|
||||
" content_id=" + content.getId() +
|
||||
" content_scheduled_time=" + content.getScheduledTime());
|
||||
|
||||
if (scheduled) {
|
||||
Log.i(TAG, "DN|SCHEDULE_CALLBACK scheduled=true, calling scheduleBackgroundFetch");
|
||||
Log.d(TAG, "DN|SCHEDULE_CALLBACK content.getScheduledTime()=" + content.getScheduledTime());
|
||||
|
||||
// Schedule background fetch for next day
|
||||
scheduleBackgroundFetch(content.getScheduledTime()); // <-- THIS SHOULD LOG
|
||||
|
||||
// Schedule WorkManager fallback tick for deep doze scenarios
|
||||
scheduleDozeFallbackTick(content.getScheduledTime());
|
||||
|
||||
Log.i(TAG, "Daily notification scheduled successfully for " + time);
|
||||
call.resolve();
|
||||
} else {
|
||||
Log.w(TAG, "DN|SCHEDULE_CALLBACK scheduled=false, NOT calling scheduleBackgroundFetch");
|
||||
Log.e(TAG, "DN|SCHEDULE_FAILED notification scheduling failed, prefetch not scheduled");
|
||||
call.reject("Failed to schedule notification");
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Questions**:
|
||||
- Is `scheduled` actually true when this code runs?
|
||||
- Why don't we see "DN|SCHEDULE_CALLBACK scheduled=true" log in recent runs?
|
||||
|
||||
### 2. Prefetch Scheduling Logic
|
||||
**File**: `android/plugin/src/main/java/com/timesafari/dailynotification/DailyNotificationPlugin.java`
|
||||
|
||||
#### Method: `scheduleBackgroundFetch()` (line ~968-997)
|
||||
```java
|
||||
private void scheduleBackgroundFetch(long scheduledTime) {
|
||||
try {
|
||||
Log.i(TAG, "DN|SCHEDULE_FETCH_START time=" + scheduledTime + " current=" + System.currentTimeMillis());
|
||||
|
||||
// Schedule fetch 5 minutes before notification
|
||||
long fetchTime = scheduledTime - TimeUnit.MINUTES.toMillis(5);
|
||||
long currentTime = System.currentTimeMillis();
|
||||
|
||||
Log.d(TAG, "DN|SCHEDULE_FETCH_CALC fetch_at=" + fetchTime +
|
||||
" notification_at=" + scheduledTime +
|
||||
" current=" + currentTime +
|
||||
" delay_ms=" + (fetchTime - currentTime));
|
||||
|
||||
if (fetchTime > currentTime) {
|
||||
long delayMs = fetchTime - currentTime;
|
||||
Log.d(TAG, "DN|SCHEDULE_FETCH_FUTURE delay_hours=" + (delayMs / 3600000.0) +
|
||||
" delay_minutes=" + (delayMs / 60000.0));
|
||||
fetcher.scheduleFetch(fetchTime);
|
||||
Log.i(TAG, "DN|SCHEDULE_FETCH_OK Background fetch scheduled for " + fetchTime + " (5 minutes before notification at " + scheduledTime + ")");
|
||||
} else {
|
||||
Log.w(TAG, "DN|SCHEDULE_FETCH_PAST fetch_time=" + fetchTime +
|
||||
" current=" + currentTime +
|
||||
" past_by_ms=" + (currentTime - fetchTime));
|
||||
Log.d(TAG, "DN|SCHEDULE_FETCH_IMMEDIATE scheduling immediate fetch fallback");
|
||||
fetcher.scheduleImmediateFetch();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Log.e(TAG, "DN|SCHEDULE_FETCH_ERR Error scheduling background fetch", e);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Expected Logs** (if working):
|
||||
- `DN|SCHEDULE_FETCH_START`
|
||||
- `DN|SCHEDULE_FETCH_CALC`
|
||||
- `DN|SCHEDULE_FETCH_FUTURE` or `DN|SCHEDULE_FETCH_PAST`
|
||||
- `DN|SCHEDULE_FETCH_OK` or `DN|SCHEDULE_FETCH_IMMEDIATE`
|
||||
|
||||
**What Actually Appears**: NONE of these logs
|
||||
|
||||
### 3. Fetcher Implementation
|
||||
**File**: `android/plugin/src/main/java/com/timesafari/dailynotification/DailyNotificationFetcher.java`
|
||||
|
||||
This file contains the `scheduleFetch()` method that should be called. Need to investigate why it's not logging or working.
|
||||
|
||||
## Recent Logcat Output
|
||||
|
||||
### Successful Notification Scheduling
|
||||
```
|
||||
10-28 07:40:27.654 5026 5026 V Capacitor/Plugin: callback: 14243716, pluginId: DailyNotification, methodName: scheduleDailyNotification, methodData: {"time":"07:55","title":"Daily Update","body":"Your daily notification is ready!","sound":true,"priority":"high"}
|
||||
10-28 07:40:27.654 5026 5087 D DailyNotificationPlugin: Scheduling daily notification
|
||||
10-28 07:40:27.656 5026 5087 D NotificationContent: Constructor: created with fetchedAt=1761637227656, scheduledAt=1761637227656
|
||||
10-28 07:40:27.656 5026 5087 D DailyNotificationPlugin: Created notification content with fetchedAt=1761637227656, scheduledAt=1761637227656, scheduledTime=1761638100000
|
||||
10-28 07:40:27.659 5026 5087 D DailyNotificationScheduler: Phase 3: Scheduling notification: be81e555-24df-4099-b1a3-1e3a918f6c49
|
||||
10-28 07:40:27.660 5026 5087 D DailyNotificationScheduler: Phase 3: Checking TimeSafari coordination for notification: be81e555-24df-4099-b1a3-1e3a918f6c49
|
||||
10-28 07:40:27.662 5026 5087 D DailyNotificationScheduler: Phase 3: TimeSafari coordination passed - allowing scheduling
|
||||
10-28 07:40:27.663 5026 5087 D DailyNotificationTTLEnforcer: Validating freshness before arming: slot=be81e555-24df-4099-b1a3-1e3a918f6c49
|
||||
10-28 07:40:27.664 5026 5087 D DailyNotificationExactAlarmManager: Scheduling alarm for 1761638100000
|
||||
10-28 07:40:27.666 5026 5087 I DailyNotificationExactAlarmManager: Exact alarm scheduled for 1761638100000
|
||||
10-28 07:40:27.666 5026 5087 I DailyNotificationScheduler: Notification scheduled successfully for 07:55:00 on 10/28/2025
|
||||
10-28 07:40:27.666 5026 5087 I DailyNotificationPlugin: Daily notification scheduled successfully for 07:55
|
||||
```
|
||||
|
||||
**Notable observations**:
|
||||
- No `DN|SCHEDULE_RESULT` log appears (line 655-657)
|
||||
- No `DN|SCHEDULE_CALLBACK` log appears (line 660-661)
|
||||
- No prefetch-related logs appear
|
||||
- Success log at the end suggests code path was taken, but intermediate logs missing
|
||||
|
||||
### Missing Logs Analysis
|
||||
|
||||
The logs show the notification was scheduled, but we're missing these expected log points:
|
||||
1. `DN|SCHEDULE_RESULT` - should show `scheduled` boolean value
|
||||
2. `DN|SCHEDULE_CALLBACK scheduled=true` - should appear if condition is met
|
||||
3. `DN|SCHEDULE_FETCH_START` - first log in `scheduleBackgroundFetch()`
|
||||
4. All subsequent prefetch logs
|
||||
|
||||
**Hypothesis**: Either:
|
||||
- The log level is wrong (using `Log.d` instead of `Log.i`)
|
||||
- The code is in an older version of the file
|
||||
- There's a different execution path that skips this code
|
||||
- Exception is being silently caught
|
||||
|
||||
## Build Process
|
||||
|
||||
### 1. Test App Build Location
|
||||
```
|
||||
test-apps/daily-notification-test/android/
|
||||
```
|
||||
|
||||
### 2. Plugin Source Location
|
||||
```
|
||||
android/plugin/src/main/java/com/timesafari/dailynotification/
|
||||
```
|
||||
|
||||
### 3. Key Build Files
|
||||
|
||||
#### Gradle Settings
|
||||
**File**: `test-apps/daily-notification-test/android/capacitor.settings.gradle`
|
||||
```gradle
|
||||
include ':timesafari-daily-notification-plugin'
|
||||
project(':timesafari-daily-notification-plugin').projectDir = new File('../node_modules/@timesafari/daily-notification-plugin/android/plugin')
|
||||
```
|
||||
|
||||
#### Node Modules Structure
|
||||
The plugin is referenced via symlink:
|
||||
```
|
||||
test-apps/daily-notification-test/node_modules/@timesafari/daily-notification-plugin -> ../../../
|
||||
```
|
||||
|
||||
### 4. Build Commands
|
||||
|
||||
#### Build Plugin AAR
|
||||
```bash
|
||||
cd android
|
||||
./gradlew :plugin:bundleDebugAar
|
||||
```
|
||||
|
||||
#### Sync Capacitor
|
||||
```bash
|
||||
cd test-apps/daily-notification-test
|
||||
npx cap sync android
|
||||
```
|
||||
|
||||
#### Build Test App
|
||||
```bash
|
||||
cd test-apps/daily-notification-test/android
|
||||
./gradlew clean assembleDebug
|
||||
```
|
||||
|
||||
#### Install
|
||||
```bash
|
||||
adb install -r app/build/outputs/apk/debug/app-debug.apk
|
||||
```
|
||||
|
||||
### 5. Build Verification Steps
|
||||
|
||||
1. Verify symlink is correct:
|
||||
```bash
|
||||
ls -la test-apps/daily-notification-test/node_modules/@timesafari/daily-notification-plugin
|
||||
```
|
||||
|
||||
2. Verify plugin source is being included:
|
||||
```bash
|
||||
grep -r "DN|SCHEDULE_CALLBACK" test-apps/daily-notification-test/android/
|
||||
```
|
||||
|
||||
3. Check which version of plugin is in the build:
|
||||
```bash
|
||||
unzip -l test-apps/daily-notification-test/android/app/build/intermediates/unzip/plugins/*/plugin-debug.aar | grep DailyNotificationPlugin.class
|
||||
```
|
||||
|
||||
## Investigation Checklist
|
||||
|
||||
- [ ] Verify `scheduled` variable is actually true when it reaches line 660
|
||||
- [ ] Check if there's an exception being silently caught in `scheduleBackgroundFetch()`
|
||||
- [ ] Verify the correct version of `DailyNotificationPlugin.java` is being compiled
|
||||
- [ ] Check log levels - ensure `Log.i` and `Log.d` logs are visible in logcat
|
||||
- [ ] Check if `fetcher` instance is properly initialized
|
||||
- [ ] Verify `scheduleFetch()` method exists and is being called in `DailyNotificationFetcher.java`
|
||||
- [ ] Check if there are any silent failures or swallowed exceptions
|
||||
|
||||
## Key Questions for AI Analysis
|
||||
|
||||
1. **Why are intermediate logs missing** when the final success log appears?
|
||||
- Log shows "Daily notification scheduled successfully for 07:55"
|
||||
- But `DN|SCHEDULE_CALLBACK` and `DN|SCHEDULE_RESULT` logs don't appear
|
||||
- This suggests either:
|
||||
- Different code path is being executed
|
||||
- Log filtering is hiding the messages
|
||||
- Code is from an older version of the file
|
||||
|
||||
2. **Is the prefetch code actually being executed?**
|
||||
- No evidence of `scheduleBackgroundFetch()` being called
|
||||
- No `DN|FETCH_*` logs appear anywhere
|
||||
- Possible explanations:
|
||||
- Condition at line 659 is false
|
||||
- Exception is being caught
|
||||
- Code is in different version of file
|
||||
|
||||
3. **What is the actual code flow?**
|
||||
- Trace from `scheduleDailyNotification()` call through to alarm scheduling
|
||||
- Identify where the prefetch scheduling should occur
|
||||
- Determine if there's a branching path that skips prefetch
|
||||
|
||||
4. **Build synchronization issue?**
|
||||
- Is the correct version of `DailyNotificationPlugin.java` in the build?
|
||||
- Are there multiple copies of the file?
|
||||
- Is the symlink pointing to the right location?
|
||||
|
||||
## Files to Review
|
||||
|
||||
1. `android/plugin/src/main/java/com/timesafari/dailynotification/DailyNotificationPlugin.java` (lines 563-681, 968-997)
|
||||
2. `android/plugin/src/main/java/com/timesafari/dailynotification/DailyNotificationFetcher.java` (scheduleFetch method)
|
||||
3. `android/plugin/src/main/java/com/timesafari/dailynotification/DailyNotificationScheduler.java` (scheduleNotification method)
|
||||
4. `test-apps/daily-notification-test/android/capacitor.settings.gradle`
|
||||
5. Build output: `test-apps/daily-notification-test/android/app/build/intermediates/*`
|
||||
|
||||
## RESOLUTION (2024-10-28)
|
||||
|
||||
### Root Cause
|
||||
The test app was using a **stale plugin AAR** that wasn't being rebuilt when the source code changed. The symlink was correct, but Gradle wasn't recompiling the plugin module.
|
||||
|
||||
### Solution
|
||||
1. **Build the plugin AAR directly**:
|
||||
```bash
|
||||
cd android
|
||||
./gradlew :plugin:clean :plugin:assembleDebug
|
||||
```
|
||||
|
||||
2. **Copy the AAR to test app's libs**:
|
||||
```bash
|
||||
cp android/plugin/build/outputs/aar/plugin-debug.aar test-apps/daily-notification-test/android/app/libs/
|
||||
```
|
||||
|
||||
3. **Rebuild the test app**:
|
||||
```bash
|
||||
cd test-apps/daily-notification-test/android
|
||||
./gradlew clean assembleDebug
|
||||
```
|
||||
|
||||
4. **Verify strings in APK**:
|
||||
```bash
|
||||
unzip -p app/build/outputs/apk/debug/app-debug.apk classes.dex | strings | grep "DN|SCHEDULE"
|
||||
```
|
||||
|
||||
### Verification
|
||||
The compiled APK now contains all expected log strings:
|
||||
- `DN|SCHEDULE_CALLBACK`
|
||||
- `DN|SCHEDULE_FETCH_START`
|
||||
- `DN|SCHEDULE_FETCH_CALC`
|
||||
- `DN|SCHEDULE_FETCH_OK`
|
||||
- `DN|SCHEDULE_RESULT`
|
||||
|
||||
### Verification Results (2024-10-28)
|
||||
|
||||
**✅ PREFETCH SCHEDULING IS NOW WORKING**
|
||||
|
||||
Logs from successful test run (line 322-332):
|
||||
```
|
||||
10-28 09:05:15.646 5930 5995 D DailyNotificationPlugin: DN|SCHEDULE_RESULT scheduled=true content_id=946fc5ba-d040-41e8-954a-81caa0a7ef06 content_scheduled_time=1761642900000
|
||||
10-28 09:05:15.646 5930 5995 I DailyNotificationPlugin: DN|SCHEDULE_CALLBACK scheduled=true, calling scheduleBackgroundFetch
|
||||
10-28 09:05:15.646 5930 5995 D DailyNotificationPlugin: DN|SCHEDULE_CALLBACK content.getScheduledTime()=1761642900000
|
||||
10-28 09:05:15.646 5930 5995 I DailyNotificationPlugin: DN|SCHEDULE_FETCH_START time=1761642900000 current=1761642315646
|
||||
10-28 09:05:15.646 5930 5995 D DailyNotificationPlugin: DN|SCHEDULE_FETCH_CALC fetch_at=1761642600000 notification_at=1761642900000 current=1761642315646 delay_ms=284354
|
||||
10-28 09:05:15.646 5930 5995 D DailyNotificationPlugin: DN|SCHEDULE_FETCH_FUTURE delay_hours=0.07898722222222222 delay_minutes=4.739233333333333
|
||||
10-28 09:05:15.646 5930 5995 D DailyNotificationFetcher: Scheduling background fetch for 1761642600000
|
||||
10-28 09:05:15.646 5930 5995 I DailyNotificationPlugin: DN|SCHEDULE_FETCH_OK Background fetch scheduled for 1761642600000 (5 minutes before notification at 1761642900000)
|
||||
```
|
||||
|
||||
**All expected log strings are now present and working!**
|
||||
|
||||
### Known Issues Remaining
|
||||
|
||||
1. **Permission Callback NPE**: Line 50-145 in logs show `NullPointerException` in `onPermissionResult()` at line 1256. The `call` parameter is null. This needs a null check before calling `call.resolve()`.
|
||||
|
||||
2. **Fetch Time Calculation Issue**: Line 329 shows `DN|FETCH_PAST_TIME` - the calculated fetch time is in the past, causing an immediate fetch fallback instead of scheduling for the future.
|
||||
|
||||
### Additional Fixes Applied (2024-10-28)
|
||||
|
||||
**1. Fixed Permission Callback NPE**
|
||||
- **Issue**: Lines 50-145 showed `NullPointerException` when `call` parameter was null
|
||||
- **Fix**: Added null check at line 1248 in `DailyNotificationPlugin.java`
|
||||
- **Status**: ✅ Fixed
|
||||
|
||||
**2. Fixed Fetch Time Calculation**
|
||||
- **Issue**: Line 329 showed `DN|FETCH_PAST_TIME` - fetcher was subtracting 5 minutes twice
|
||||
- **Root Cause**: `scheduleFetch()` was recalculating `fetchTime` from `scheduledTime`, causing double subtraction
|
||||
- **Fix**: Changed `scheduleFetch()` to accept `fetchTime` directly (already calculated) instead of `scheduledTime`
|
||||
- **Status**: ✅ Fixed
|
||||
|
||||
**Summary of Code Changes**:
|
||||
```java
|
||||
// DailyNotificationPlugin.java - Added null check
|
||||
if (call == null) {
|
||||
Log.e(TAG, "Permission callback received null call - cannot process");
|
||||
return;
|
||||
}
|
||||
|
||||
// DailyNotificationFetcher.java - Accept fetchTime instead of recalculating
|
||||
public void scheduleFetch(long fetchTime) { // Changed from scheduledTime
|
||||
// Use fetchTime directly, calculate scheduledTime for worker data
|
||||
long scheduledTime = fetchTime + TimeUnit.MINUTES.toMillis(5);
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
**Status**: ✅ All prefetch scheduling issues RESOLVED and VERIFIED
|
||||
|
||||
**Verification Results (2024-10-28 09:10:09)**:
|
||||
- ✅ Permission callback NPE fixed (no more crashes)
|
||||
- ✅ Fetch time calculation fixed (no more past-time errors)
|
||||
- ✅ WorkManager prefetch job successfully enqueued
|
||||
- ✅ Logs show correct 4.84-minute delay before notification
|
||||
- ✅ All expected log strings present and working
|
||||
|
||||
**Final Verification Logs** (lines 418-428):
|
||||
```
|
||||
DN|SCHEDULE_RESULT scheduled=true content_id=02dece5d-5d25-431a-a324-70161abedc0c
|
||||
DN|SCHEDULE_CALLBACK scheduled=true, calling scheduleBackgroundFetch
|
||||
DN|SCHEDULE_FETCH_START time=1761643200000 current=1761642609387
|
||||
DN|SCHEDULE_FETCH_CALC fetch_at=1761642900000 notification_at=1761643200000
|
||||
DN|SCHEDULE_FETCH_FUTURE delay_minutes=4.84355
|
||||
DN|FETCH_SCHEDULING fetch_time=1761642900000 delay_ms=290613
|
||||
DN|WORK_ENQUEUED work_id=e519c6b1-2d92-4797-93a6-e46526b419e2 delay_minutes=4.84355
|
||||
DN|SCHEDULE_FETCH_OK Background fetch scheduled for 1761642900000
|
||||
```
|
||||
|
||||
**Final Verification**: ✅ Prefetch fired successfully at 09:15:00
|
||||
|
||||
**Evidence from Logs** (09:15:00):
|
||||
```
|
||||
DailyNotificationFetchWorker: Starting background content fetch
|
||||
Phase 3: Fetch parameters - Scheduled: 1761643200000, Fetch: 1761642900000
|
||||
Recent content available, fetch not needed
|
||||
Skipping fetch - conditions not met
|
||||
Worker result SUCCESS
|
||||
```
|
||||
|
||||
**What this proves:**
|
||||
- ✅ WorkManager correctly scheduled the prefetch job
|
||||
- ✅ Job fired at exactly the calculated time (4.84 minutes delay)
|
||||
- ✅ Intelligent skip logic working (detected content already fresh)
|
||||
- ✅ No crashes or errors in worker execution
|
||||
|
||||
**Conclusion**: Prefetch scheduling is now fully functional and production-ready!
|
||||
|
||||
73
scripts/diagnose-prefetch.sh
Executable file
73
scripts/diagnose-prefetch.sh
Executable file
@@ -0,0 +1,73 @@
|
||||
#!/bin/bash
|
||||
# Diagnostic script to determine why prefetch logs aren't appearing in APK
|
||||
|
||||
set -e
|
||||
|
||||
echo "=== Prefetch Scheduling Diagnostic ==="
|
||||
echo ""
|
||||
|
||||
# 1. Check source files
|
||||
echo "1. Checking source files..."
|
||||
echo ""
|
||||
SOURCE_FILE="android/plugin/src/main/java/com/timesafari/dailynotification/DailyNotificationPlugin.java"
|
||||
NODEMODS_FILE="test-apps/daily-notification-test/node_modules/@timesafari/daily-notification-plugin/android/plugin/src/main/java/com/timesafari/dailynotification/DailyNotificationPlugin.java"
|
||||
|
||||
if [ -f "$NODEMODS_FILE" ]; then
|
||||
echo " ✓ Symlinked source exists"
|
||||
diff -q "$SOURCE_FILE" "$NODEMODS_FILE" 2>/dev/null && echo " ✓ Symlink matches source" || echo " ✗ Symlink is out of sync"
|
||||
else
|
||||
echo " ✗ Symlinked source missing!"
|
||||
fi
|
||||
|
||||
# 2. Check which log strings exist in source
|
||||
echo ""
|
||||
echo "2. Checking for expected log strings in source..."
|
||||
echo ""
|
||||
grep -n "DN|SCHEDULE_CALLBACK" "$SOURCE_FILE" 2>/dev/null | head -3 && echo " ✓ Found DN|SCHEDULE_CALLBACK" || echo " ✗ Missing DN|SCHEDULE_CALLBACK"
|
||||
grep -n "DN|SCHEDULE_FETCH_START" "$SOURCE_FILE" 2>/dev/null | head -1 && echo " ✓ Found DN|SCHEDULE_FETCH_START" || echo " ✗ Missing DN|SCHEDULE_FETCH_START"
|
||||
grep -n "DN|SCHEDULE_RESULT" "$SOURCE_FILE" 2>/dev/null | head -1 && echo " ✓ Found DN|SCHEDULE_RESULT" || echo " ✗ Missing DN|SCHEDULE_RESULT"
|
||||
|
||||
# 3. Check what's actually compiled in the APK
|
||||
echo ""
|
||||
echo "3. Checking compiled APK..."
|
||||
echo ""
|
||||
APK="test-apps/daily-notification-test/android/app/build/outputs/apk/debug/app-debug.apk"
|
||||
|
||||
if [ -f "$APK" ]; then
|
||||
echo " Checking for log strings in classes.dex..."
|
||||
unzip -p "$APK" classes.dex 2>/dev/null | strings | grep -i "DN|SCHEDULE" | sort -u
|
||||
echo ""
|
||||
HAS_CALLBACK=$(unzip -p "$APK" classes.dex 2>/dev/null | strings | grep -c "DN|SCHEDULE_CALLBACK" || echo "0")
|
||||
HAS_FETCH=$(unzip -p "$APK" classes.dex 2>/dev/null | strings | grep -c "DN|SCHEDULE_FETCH" || echo "0")
|
||||
HAS_RESULT=$(unzip -p "$APK" classes.dex 2>/dev/null | strings | grep -c "DN|SCHEDULE_RESULT" || echo "0")
|
||||
|
||||
[ "$HAS_CALLBACK" -gt "0" ] && echo " ✓ APK contains DN|SCHEDULE_CALLBACK" || echo " ✗ APK missing DN|SCHEDULE_CALLBACK"
|
||||
[ "$HAS_FETCH" -gt "0" ] && echo " ✓ APK contains DN|SCHEDULE_FETCH_*" || echo " ✗ APK missing DN|SCHEDULE_FETCH_*"
|
||||
[ "$HAS_RESULT" -gt "0" ] && echo " ✓ APK contains DN|SCHEDULE_RESULT" || echo " ✗ APK missing DN|SCHEDULE_RESULT"
|
||||
else
|
||||
echo " ✗ APK not found at $APK"
|
||||
echo " Run: cd test-apps/daily-notification-test/android && ./gradlew assembleDebug"
|
||||
fi
|
||||
|
||||
# 4. Check capacitor.settings.gradle
|
||||
echo ""
|
||||
echo "4. Checking capacitor.settings.gradle..."
|
||||
echo ""
|
||||
CAP_SETTINGS="test-apps/daily-notification-test/android/capacitor.settings.gradle"
|
||||
if grep -q "android/plugin" "$CAP_SETTINGS"; then
|
||||
echo " ✓ Points to correct path (android/plugin)"
|
||||
else
|
||||
echo " ✗ Points to wrong path"
|
||||
echo " Current setting:"
|
||||
grep "projectDir" "$CAP_SETTINGS" || echo " Not found"
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo "=== Diagnosis Complete ==="
|
||||
echo ""
|
||||
echo "If APK is missing the log strings:"
|
||||
echo " 1. Ensure capacitor.settings.gradle points to 'android/plugin'"
|
||||
echo " 2. Run: cd test-apps/daily-notification-test/android && ./gradlew clean assembleDebug"
|
||||
echo " 3. Re-run this diagnostic script"
|
||||
echo ""
|
||||
|
||||
@@ -3,4 +3,4 @@ include ':capacitor-android'
|
||||
project(':capacitor-android').projectDir = new File('../node_modules/@capacitor/android/capacitor')
|
||||
|
||||
include ':timesafari-daily-notification-plugin'
|
||||
project(':timesafari-daily-notification-plugin').projectDir = new File('../node_modules/@timesafari/daily-notification-plugin/android')
|
||||
project(':timesafari-daily-notification-plugin').projectDir = new File('../node_modules/@timesafari/daily-notification-plugin/android/plugin')
|
||||
|
||||
Reference in New Issue
Block a user