fix(ios): iOS 13.0 compatibility and test app UI unification
Fixed iOS 13.0 compatibility issue in test harness by replacing Logger (iOS 14+) with os_log (iOS 13+). Fixed build script to correctly detect and sync Capacitor config from App subdirectory. Unified both Android and iOS test app UIs to use www/index.html as the canonical source. Changes: - DailyNotificationBackgroundTaskTestHarness: Replace Logger with os_log for iOS 13.0 deployment target compatibility - build-ios-test-app.sh: Fix Capacitor sync path detection to check both current directory and App/ subdirectory for config files - test-apps: Update both Android and iOS test apps to use www/index.html as the canonical UI source for consistency This ensures the plugin builds on iOS 13.0+ and both test apps provide the same testing experience across platforms.
This commit is contained in:
@@ -46,16 +46,16 @@ class DailyNotificationBackgroundTaskTestHarness {
|
||||
|
||||
// MARK: - Structured Logging
|
||||
|
||||
/// Swift Logger categories for structured logging
|
||||
static let pluginLogger = Logger(subsystem: "com.timesafari.dailynotification", category: "plugin")
|
||||
static let fetchLogger = Logger(subsystem: "com.timesafari.dailynotification", category: "fetch")
|
||||
static let schedulerLogger = Logger(subsystem: "com.timesafari.dailynotification", category: "scheduler")
|
||||
static let storageLogger = Logger(subsystem: "com.timesafari.dailynotification", category: "storage")
|
||||
/// OSLog categories for structured logging (iOS 13.0+ compatible)
|
||||
private static let pluginLog = OSLog(subsystem: "com.timesafari.dailynotification", category: "plugin")
|
||||
private static let fetchLog = OSLog(subsystem: "com.timesafari.dailynotification", category: "fetch")
|
||||
private static let schedulerLog = OSLog(subsystem: "com.timesafari.dailynotification", category: "scheduler")
|
||||
private static let storageLog = OSLog(subsystem: "com.timesafari.dailynotification", category: "storage")
|
||||
|
||||
/// Log telemetry snapshot for validation
|
||||
static func logTelemetrySnapshot(prefix: String = "DNP-") {
|
||||
// Phase 2: Capture telemetry counters from structured logs
|
||||
fetchLogger.info("Telemetry snapshot: \(prefix)prefetch_scheduled_total, \(prefix)prefetch_executed_total, \(prefix)prefetch_success_total")
|
||||
os_log("[DNP-FETCH] Telemetry snapshot: %{public}@prefetch_scheduled_total, %{public}@prefetch_executed_total, %{public}@prefetch_success_total", log: fetchLog, type: .info, prefix, prefix, prefix)
|
||||
}
|
||||
|
||||
// MARK: - Registration
|
||||
@@ -106,16 +106,16 @@ class DailyNotificationBackgroundTaskTestHarness {
|
||||
|
||||
do {
|
||||
try BGTaskScheduler.shared.submit(request)
|
||||
fetchLogger.info("[DNP-FETCH] BGAppRefreshTask scheduled (earliestBeginDate=\(String(describing: request.earliestBeginDate)))")
|
||||
os_log("[DNP-FETCH] BGAppRefreshTask scheduled (earliestBeginDate=%{public}@)", log: fetchLog, type: .info, String(describing: request.earliestBeginDate))
|
||||
return true
|
||||
} catch {
|
||||
// Handle simulator limitation (Code=1 is expected on simulator)
|
||||
if let nsError = error as NSError?, nsError.domain == "BGTaskSchedulerErrorDomain", nsError.code == 1 {
|
||||
fetchLogger.warning("[DNP-FETCH] BGTask scheduling failed on simulator (expected): Code=1 notPermitted")
|
||||
os_log("[DNP-FETCH] BGTask scheduling failed on simulator (expected): Code=1 notPermitted", log: fetchLog, type: .default)
|
||||
print("[DNP-FETCH] NOTE: BGTaskScheduler doesn't work on simulator - this is expected. Use Xcode → Debug → Simulate Background Fetch for testing.")
|
||||
return false
|
||||
}
|
||||
fetchLogger.error("[DNP-FETCH] Failed to schedule BGAppRefreshTask: \(error.localizedDescription)")
|
||||
os_log("[DNP-FETCH] Failed to schedule BGAppRefreshTask: %{public}@", log: fetchLog, type: .error, error.localizedDescription)
|
||||
print("[DNP-FETCH] Failed to schedule BGAppRefreshTask: \(error)")
|
||||
return false
|
||||
}
|
||||
@@ -130,7 +130,7 @@ class DailyNotificationBackgroundTaskTestHarness {
|
||||
// In real implementation, check if this request matches the notificationId
|
||||
// For now, cancel all prefetch tasks (Phase 1: single notification)
|
||||
BGTaskScheduler.shared.cancel(taskRequestWithIdentifier: prefetchTaskIdentifier)
|
||||
fetchLogger.info("[DNP-FETCH] Cancelled existing pending task for notificationId=\(notificationId)")
|
||||
os_log("[DNP-FETCH] Cancelled existing pending task for notificationId=%{public}@", log: fetchLog, type: .info, notificationId)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -149,7 +149,7 @@ class DailyNotificationBackgroundTaskTestHarness {
|
||||
semaphore.wait()
|
||||
|
||||
if pendingCount > 1 {
|
||||
fetchLogger.warning("[DNP-FETCH] WARNING: Multiple pending tasks detected (\(pendingCount)) - expected 1")
|
||||
os_log("[DNP-FETCH] WARNING: Multiple pending tasks detected (%d) - expected 1", log: fetchLog, type: .default, pendingCount)
|
||||
return false
|
||||
}
|
||||
|
||||
@@ -203,7 +203,7 @@ class DailyNotificationBackgroundTaskTestHarness {
|
||||
/// This is called by the system when the background task is launched.
|
||||
/// Replace PrefetchOperation with your actual prefetch logic.
|
||||
private static func handlePrefetchTask(task: BGAppRefreshTask) {
|
||||
fetchLogger.info("[DNP-FETCH] BGTask handler invoked (task.identifier=\(task.identifier))")
|
||||
os_log("[DNP-FETCH] BGTask handler invoked (task.identifier=%{public}@)", log: fetchLog, type: .info, task.identifier)
|
||||
|
||||
// STEP 1: Schedule the next task IMMEDIATELY (Apple best practice)
|
||||
// This ensures continuity even if app is terminated shortly after
|
||||
@@ -219,14 +219,14 @@ class DailyNotificationBackgroundTaskTestHarness {
|
||||
|
||||
// STEP 4: Set expiration handler (called if iOS terminates task early, ~30 seconds)
|
||||
task.expirationHandler = {
|
||||
fetchLogger.warning("[DNP-FETCH] Task expired - cancelling operations")
|
||||
os_log("[DNP-FETCH] Task expired - cancelling operations", log: fetchLog, type: .default)
|
||||
operation.cancel()
|
||||
|
||||
// Ensure task is marked complete even on expiration
|
||||
if !taskCompleted {
|
||||
taskCompleted = true
|
||||
task.setTaskCompleted(success: false)
|
||||
fetchLogger.info("[DNP-FETCH] Task marked complete (success=false) due to expiration")
|
||||
os_log("[DNP-FETCH] Task marked complete (success=false) due to expiration", log: fetchLog, type: .info)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -239,9 +239,9 @@ class DailyNotificationBackgroundTaskTestHarness {
|
||||
if !taskCompleted {
|
||||
taskCompleted = true
|
||||
task.setTaskCompleted(success: success)
|
||||
fetchLogger.info("[DNP-FETCH] Task marked complete (success=\(success))")
|
||||
os_log("[DNP-FETCH] Task marked complete (success=%{public}@)", log: fetchLog, type: .info, success ? "true" : "false")
|
||||
} else {
|
||||
fetchLogger.warning("[DNP-FETCH] WARNING: Attempted to complete task twice")
|
||||
os_log("[DNP-FETCH] WARNING: Attempted to complete task twice", log: fetchLog, type: .default)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -262,12 +262,12 @@ class DailyNotificationBackgroundTaskTestHarness {
|
||||
class PrefetchOperation: Operation {
|
||||
|
||||
var isFailed = false
|
||||
private let fetchLogger = Logger(subsystem: "com.timesafari.dailynotification", category: "fetch")
|
||||
private static let fetchLog = OSLog(subsystem: "com.timesafari.dailynotification", category: "fetch")
|
||||
|
||||
override func main() {
|
||||
if isCancelled { return }
|
||||
|
||||
fetchLogger.info("[DNP-FETCH] PrefetchOperation: starting fetch...")
|
||||
os_log("[DNP-FETCH] PrefetchOperation: starting fetch...", log: Self.fetchLog, type: .info)
|
||||
|
||||
// Simulate some work
|
||||
// In real implementation, this would be:
|
||||
@@ -287,11 +287,11 @@ class PrefetchOperation: Operation {
|
||||
let success = true // Replace with actual fetch result
|
||||
|
||||
if success {
|
||||
fetchLogger.info("[DNP-FETCH] PrefetchOperation: fetch success")
|
||||
os_log("[DNP-FETCH] PrefetchOperation: fetch success", log: Self.fetchLog, type: .info)
|
||||
// In real implementation: persist cache here before completion
|
||||
} else {
|
||||
isFailed = true
|
||||
fetchLogger.error("[DNP-FETCH] PrefetchOperation: fetch failed")
|
||||
os_log("[DNP-FETCH] PrefetchOperation: fetch failed", log: Self.fetchLog, type: .error)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user