Fix iOS build errors and test app setup
- Fix async/await usage in background fetch handler - Fix Core Data metadata access errors - Replace SQLITE_TRANSIENT with nil for Swift compatibility - Fix PermissionStatus interface and type casts in test app - Add iOS setup documentation to BUILDING.md - Update iOS sync workflow to handle Podfile regeneration Resolves all iOS compilation errors and improves test app setup process.
This commit is contained in:
@@ -419,58 +419,58 @@ public class DailyNotificationPlugin: CAPPlugin {
|
||||
// Phase 3: Check for JWT-signed fetcher configuration
|
||||
// If native fetcher is configured, use it; otherwise fall back to dummy content
|
||||
let nativeFetcherConfig = UserDefaults.standard.string(forKey: "native_fetcher_config")
|
||||
let content: NotificationContent
|
||||
|
||||
if let configJson = nativeFetcherConfig,
|
||||
let configData = configJson.data(using: .utf8),
|
||||
let config = try? JSONSerialization.jsonObject(with: configData) as? [String: Any],
|
||||
let apiBaseUrl = config["apiBaseUrl"] as? String,
|
||||
let activeDid = config["activeDid"] as? String,
|
||||
let jwtToken = config["jwtToken"] as? String {
|
||||
// Phase 3: JWT-signed fetcher is configured - attempt HTTP fetch
|
||||
print("DNP-FETCH: Using JWT-signed fetcher (apiBaseUrl=\(apiBaseUrl), activeDid=\(activeDid.prefix(30))...)")
|
||||
// Save content to storage via state actor (thread-safe)
|
||||
Task {
|
||||
let content: NotificationContent
|
||||
|
||||
// Attempt to fetch content from TimeSafari API
|
||||
// Note: This is a minimal implementation - can be extended with full API client
|
||||
do {
|
||||
let fetchedContent = try await fetchContentFromAPI(
|
||||
apiBaseUrl: apiBaseUrl,
|
||||
activeDid: activeDid,
|
||||
jwtToken: jwtToken
|
||||
)
|
||||
content = fetchedContent
|
||||
print("DNP-FETCH: Successfully fetched content from API")
|
||||
} catch {
|
||||
// Fallback to dummy content on fetch failure
|
||||
print("DNP-FETCH: API fetch failed (\(error.localizedDescription)), using fallback content")
|
||||
if let configJson = nativeFetcherConfig,
|
||||
let configData = configJson.data(using: .utf8),
|
||||
let config = try? JSONSerialization.jsonObject(with: configData) as? [String: Any],
|
||||
let apiBaseUrl = config["apiBaseUrl"] as? String,
|
||||
let activeDid = config["activeDid"] as? String,
|
||||
let jwtToken = config["jwtToken"] as? String {
|
||||
// Phase 3: JWT-signed fetcher is configured - attempt HTTP fetch
|
||||
print("DNP-FETCH: Using JWT-signed fetcher (apiBaseUrl=\(apiBaseUrl), activeDid=\(activeDid.prefix(30))...)")
|
||||
|
||||
// Attempt to fetch content from TimeSafari API
|
||||
// Note: This is a minimal implementation - can be extended with full API client
|
||||
do {
|
||||
let fetchedContent = try await fetchContentFromAPI(
|
||||
apiBaseUrl: apiBaseUrl,
|
||||
activeDid: activeDid,
|
||||
jwtToken: jwtToken
|
||||
)
|
||||
content = fetchedContent
|
||||
print("DNP-FETCH: Successfully fetched content from API")
|
||||
} catch {
|
||||
// Fallback to dummy content on fetch failure
|
||||
print("DNP-FETCH: API fetch failed (\(error.localizedDescription)), using fallback content")
|
||||
content = NotificationContent(
|
||||
id: "fallback_\(Date().timeIntervalSince1970)",
|
||||
title: "Daily Update",
|
||||
body: "Your daily notification is ready",
|
||||
scheduledTime: Int64(Date().timeIntervalSince1970 * 1000) + (5 * 60 * 1000),
|
||||
fetchedAt: Int64(Date().timeIntervalSince1970 * 1000),
|
||||
url: nil,
|
||||
payload: ["fetchError": error.localizedDescription],
|
||||
etag: nil
|
||||
)
|
||||
}
|
||||
} else {
|
||||
// Fallback: Dummy content fetch (no network)
|
||||
print("DNP-FETCH: Using dummy content (native fetcher not configured)")
|
||||
content = NotificationContent(
|
||||
id: "fallback_\(Date().timeIntervalSince1970)",
|
||||
id: "dummy_\(Date().timeIntervalSince1970)",
|
||||
title: "Daily Update",
|
||||
body: "Your daily notification is ready",
|
||||
scheduledTime: Int64(Date().timeIntervalSince1970 * 1000) + (5 * 60 * 1000),
|
||||
fetchedAt: Int64(Date().timeIntervalSince1970 * 1000),
|
||||
url: nil,
|
||||
payload: ["fetchError": error.localizedDescription],
|
||||
payload: nil,
|
||||
etag: nil
|
||||
)
|
||||
}
|
||||
} else {
|
||||
// Fallback: Dummy content fetch (no network)
|
||||
print("DNP-FETCH: Using dummy content (native fetcher not configured)")
|
||||
content = NotificationContent(
|
||||
id: "dummy_\(Date().timeIntervalSince1970)",
|
||||
title: "Daily Update",
|
||||
body: "Your daily notification is ready",
|
||||
scheduledTime: Int64(Date().timeIntervalSince1970 * 1000) + (5 * 60 * 1000),
|
||||
fetchedAt: Int64(Date().timeIntervalSince1970 * 1000),
|
||||
url: nil,
|
||||
payload: nil,
|
||||
etag: nil
|
||||
)
|
||||
}
|
||||
|
||||
// Save content to storage via state actor (thread-safe)
|
||||
Task {
|
||||
do {
|
||||
// Use the content (either from JWT fetcher or dummy)
|
||||
if #available(iOS 13.0, *) {
|
||||
@@ -513,11 +513,16 @@ public class DailyNotificationPlugin: CAPPlugin {
|
||||
|
||||
// Phase 3.3: Schedule next background task
|
||||
// Calculate next fetch time based on notification schedule
|
||||
if let nextScheduledTime = self.getNextScheduledNotificationTime() {
|
||||
self.scheduleBackgroundFetch(scheduledTime: nextScheduledTime)
|
||||
print("DNP-FETCH: Next background fetch scheduled")
|
||||
if let scheduler = self.scheduler {
|
||||
let nextScheduledTime = await scheduler.getNextNotificationTime()
|
||||
if let nextTime = nextScheduledTime {
|
||||
self.scheduleBackgroundFetch(scheduledTime: nextTime)
|
||||
print("DNP-FETCH: Next background fetch scheduled")
|
||||
} else {
|
||||
print("DNP-FETCH: No future notifications found, skipping next task schedule")
|
||||
}
|
||||
} else {
|
||||
print("DNP-FETCH: No future notifications found, skipping next task schedule")
|
||||
print("DNP-FETCH: Scheduler not available, skipping next task schedule")
|
||||
}
|
||||
|
||||
guard !taskCompleted else { return }
|
||||
@@ -575,10 +580,13 @@ public class DailyNotificationPlugin: CAPPlugin {
|
||||
|
||||
// Phase 3.3: Schedule next background task if needed
|
||||
// For notify task, schedule next occurrence if applicable
|
||||
if let nextScheduledTime = self.getNextScheduledNotificationTime() {
|
||||
// Calculate next notify task time (if applicable)
|
||||
// Note: Notify tasks are typically scheduled less frequently than fetch tasks
|
||||
print("DNP-NOTIFY: Next notification scheduled at \(nextScheduledTime)")
|
||||
if let scheduler = self.scheduler {
|
||||
let nextScheduledTime = await scheduler.getNextNotificationTime()
|
||||
if let nextTime = nextScheduledTime {
|
||||
// Calculate next notify task time (if applicable)
|
||||
// Note: Notify tasks are typically scheduled less frequently than fetch tasks
|
||||
print("DNP-NOTIFY: Next notification scheduled at \(nextTime)")
|
||||
}
|
||||
}
|
||||
|
||||
guard !taskCompleted else { return }
|
||||
@@ -1091,7 +1099,7 @@ public class DailyNotificationPlugin: CAPPlugin {
|
||||
scheduler: scheduler,
|
||||
storage: self.storage,
|
||||
stateActor: await self.stateActor,
|
||||
scheduleBackgroundFetch: { [weak self] scheduledTime in
|
||||
scheduleBackgroundFetch: { [weak self] (scheduledTime: Int64) -> Void in
|
||||
self?.scheduleBackgroundFetch(scheduledTime: scheduledTime)
|
||||
}
|
||||
)
|
||||
@@ -1532,8 +1540,8 @@ public class DailyNotificationPlugin: CAPPlugin {
|
||||
// User must check in Settings app
|
||||
|
||||
// Delegate storage access to storage service
|
||||
let lastFetchExecution = storage?.getLastSuccessfulRun() ?? NSNull()
|
||||
let lastNotifyExecution = storage?.getLastNotifyExecution() ?? NSNull()
|
||||
let lastFetchExecution: Any = storage?.getLastSuccessfulRun() ?? NSNull()
|
||||
let lastNotifyExecution: Any = storage?.getLastNotifyExecution() ?? NSNull()
|
||||
|
||||
let result: [String: Any] = [
|
||||
"fetchTaskRegistered": true, // Assumed registered if setupBackgroundTasks() was called
|
||||
@@ -1630,6 +1638,7 @@ public class DailyNotificationPlugin: CAPPlugin {
|
||||
|
||||
// Get channelId from call (optional, for API parity with Android)
|
||||
// iOS doesn't have per-channel control, so check app-wide notification authorization
|
||||
let channelId = call.getString("channelId") ?? "default"
|
||||
Task {
|
||||
// Delegate to scheduler for permission status check
|
||||
let status = await scheduler.checkPermissionStatus()
|
||||
@@ -1677,9 +1686,6 @@ public class DailyNotificationPlugin: CAPPlugin {
|
||||
}
|
||||
}
|
||||
}
|
||||
call.reject("Invalid settings URL")
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update notification settings
|
||||
|
||||
Reference in New Issue
Block a user