{"id":18060168,"url":"https://github.com/fatbobman/icloudsyncstatuskit","last_synced_at":"2026-01-06T07:09:26.561Z","repository":{"id":259861426,"uuid":"879661391","full_name":"fatbobman/iCloudSyncStatusKit","owner":"fatbobman","description":"A Swift library that monitors the iCloud account status and responds to synchronization events when using Core Data with CloudKit. ","archived":false,"fork":false,"pushed_at":"2024-10-30T10:08:49.000Z","size":19,"stargazers_count":82,"open_issues_count":3,"forks_count":0,"subscribers_count":3,"default_branch":"main","last_synced_at":"2025-04-02T19:08:12.612Z","etag":null,"topics":["cloudkit","coredata","swift","swift-package","swiftui"],"latest_commit_sha":null,"homepage":"","language":"Swift","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/fatbobman.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null},"funding":{"github":null,"patreon":"fatbobman","open_collective":null,"ko_fi":null,"tidelift":null,"community_bridge":null,"liberapay":null,"issuehunt":null,"lfx_crowdfunding":null,"polar":null,"buy_me_a_coffee":"fatbobman","thanks_dev":null,"custom":["https://afdian.com","https://www.paypal.com/paypalme/fatbobman"]}},"created_at":"2024-10-28T10:24:33.000Z","updated_at":"2025-04-02T04:49:51.000Z","dependencies_parsed_at":"2024-12-27T02:06:43.771Z","dependency_job_id":"0991c451-7122-4a2f-be23-5bb129befe23","html_url":"https://github.com/fatbobman/iCloudSyncStatusKit","commit_stats":null,"previous_names":["fatbobman/icloudsyncstatuskit"],"tags_count":2,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fatbobman%2FiCloudSyncStatusKit","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fatbobman%2FiCloudSyncStatusKit/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fatbobman%2FiCloudSyncStatusKit/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fatbobman%2FiCloudSyncStatusKit/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/fatbobman","download_url":"https://codeload.github.com/fatbobman/iCloudSyncStatusKit/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248112621,"owners_count":21049687,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["cloudkit","coredata","swift","swift-package","swiftui"],"created_at":"2024-10-31T04:06:17.717Z","updated_at":"2026-01-06T07:09:26.556Z","avatar_url":"https://github.com/fatbobman.png","language":"Swift","funding_links":["https://patreon.com/fatbobman","https://buymeacoffee.com/fatbobman","https://afdian.com","https://www.paypal.com/paypalme/fatbobman"],"categories":[],"sub_categories":[],"readme":"# iCloudSyncStatusKit\n\nA Swift library that monitors iCloud account status, network connectivity, iCloud Drive availability, and synchronization events when using Core Data with CloudKit.\n\n## Features\n\n- **Network Status Monitoring**: Real-time network connectivity detection with interface type (WiFi/Cellular/Ethernet)\n- **Account Status Monitoring**: Check if the iCloud account is available and handle unavailable states\n- **iCloud Drive Detection**: Monitor iCloud Drive availability separately from account status\n- **Synchronization Event Handling**: Monitor importing, exporting, setup, and idle states during data synchronization\n- **Selective Monitoring**: Use `MonitoringOptions` to enable only the features you need\n- **Error Handling**: Handle specific CloudKit errors, such as `quotaExceeded`\n- **Low Data Mode Detection**: Detect constrained and expensive network conditions\n- **Logging Support**: Optional logging of synchronization events for debugging purposes\n\n## Requirements\n\n| API | Swift | iOS | macOS | watchOS | tvOS | visionOS |\n|-----|-------|-----|-------|---------|------|----------|\n| `SyncStatusAsyncManager` (Modern) | 6.2+ | 17.0+ | 14.0+ | 10.0+ | 17.0+ | 1.0+ |\n| `SyncStatusManager` (Legacy) | 6.0+ | 14.0+ | 11.0+ | - | - | - |\n\n## Installation\n\n### Swift Package Manager\n\nAdd the package to your `Package.swift` file:\n\n```swift\ndependencies: [\n    .package(url: \"https://github.com/fatbobman/iCloudSyncStatusKit.git\", from: \"1.0.0\")\n]\n```\n\nOr add it via Xcode:\n\n1. Go to **File \u003e Add Packages...**\n2. Enter the repository URL: `https://github.com/fatbobman/iCloudSyncStatusKit.git`\n3. Choose the version and add the package to your project.\n\n---\n\n## Modern API (iOS 17+, Swift 6.2+)\n\n### SyncStatusAsyncManager\n\nThe modern API uses the **Observation** framework and **async/await** for reactive state management.\n\n### Import the Library\n\n```swift\nimport iCloudSyncStatusKit\n```\n\n### Initialize SyncStatusAsyncManager\n\n```swift\n// Full monitoring (default)\n@State private var syncManager = SyncStatusAsyncManager(\n    cloudKitContainerID: \"iCloud.com.yourcompany.yourapp\"\n)\n\n// Selective monitoring with MonitoringOptions\n@State private var syncManager = SyncStatusAsyncManager(\n    monitoringOptions: [.network, .account, .cloudDrive],\n    cloudKitContainerID: \"iCloud.com.yourcompany.yourapp\"\n)\n```\n\n### MonitoringOptions\n\nControl which status types to monitor using `MonitoringOptions`:\n\n```swift\n// Individual options\n.network      // Network connectivity via NWPathMonitor\n.account      // iCloud account status\n.syncEvent    // CloudKit sync events (requires cloudKitContainerID)\n.cloudDrive   // iCloud Drive availability\n\n// Preset combinations\n.all          // All options enabled\n.basic        // Network + Account only (lightweight)\n.default      // Network + Account + CloudDrive\n.syncFocused  // Network + Account + SyncEvent\n```\n\n**Usage Example:**\n\n```swift\n// Only monitor network and account (no CloudKit sync events)\nlet manager = SyncStatusAsyncManager(\n    monitoringOptions: .basic\n)\n\n// Full monitoring for CloudKit-enabled apps\nlet manager = SyncStatusAsyncManager(\n    monitoringOptions: .all,\n    cloudKitContainerID: \"iCloud.com.yourcompany.yourapp\"\n)\n```\n\n### Basic Usage with SwiftUI\n\n```swift\nstruct ContentView: View {\n    @State private var syncManager = SyncStatusAsyncManager(\n        monitoringOptions: .all,\n        cloudKitContainerID: \"iCloud.com.yourcompany.yourapp\"\n    )\n\n    var body: some View {\n        VStack(spacing: 16) {\n            // Network Status\n            HStack {\n                Image(systemName: syncManager.isNetworkConnected ? \"wifi\" : \"wifi.slash\")\n                Text(syncManager.isNetworkConnected ? \"Connected\" : \"Disconnected\")\n            }\n\n            // Account Status\n            HStack {\n                Image(systemName: syncManager.isAccountAvailable ? \"person.crop.circle.badge.checkmark\" : \"person.crop.circle.badge.xmark\")\n                Text(syncManager.isAccountAvailable ? \"iCloud Available\" : \"iCloud Unavailable\")\n            }\n\n            // iCloud Drive Status\n            HStack {\n                Image(systemName: syncManager.isCloudDriveAvailable ? \"icloud.fill\" : \"icloud.slash\")\n                Text(syncManager.isCloudDriveAvailable ? \"iCloud Drive On\" : \"iCloud Drive Off\")\n            }\n\n            // Sync Status\n            if syncManager.isSyncing {\n                ProgressView(\"Syncing...\")\n            }\n\n            // Comprehensive Status\n            if syncManager.environmentStatus.isSyncReady {\n                Text(\"✅ Ready to sync\")\n                    .foregroundStyle(.green)\n            }\n        }\n    }\n}\n```\n\n### Available Properties\n\n| Property | Type | Description |\n|----------|------|-------------|\n| `networkStatus` | `NetworkStatus` | Detailed network status including interface type |\n| `accountStatus` | `AccountStatus` | iCloud account availability status |\n| `syncEvent` | `SyncEvent` | Current sync event (importing/exporting/setup/idle) |\n| `isCloudDriveAvailable` | `Bool` | Whether iCloud Drive is enabled |\n| `environmentStatus` | `SyncEnvironmentStatus` | Combined status with convenience properties |\n| `isNetworkConnected` | `Bool` | Simple network connectivity check |\n| `isAccountAvailable` | `Bool` | Simple account availability check |\n| `isSyncing` | `Bool` | Whether sync is in progress |\n| `monitoringOptions` | `MonitoringOptions` | Current monitoring configuration |\n\n### iCloud Drive vs iCloud Account\n\n**Important**: iCloud Drive availability is separate from iCloud account status.\n\n```swift\n// User may have iCloud account available but iCloud Drive disabled\nif syncManager.isAccountAvailable \u0026\u0026 !syncManager.isCloudDriveAvailable {\n    // Account is signed in, but iCloud Drive is turned off in Settings\n    print(\"Please enable iCloud Drive in Settings\")\n}\n```\n\n| Scenario | `isAccountAvailable` | `isCloudDriveAvailable` |\n|----------|---------------------|------------------------|\n| Not signed in | ❌ | ❌ |\n| Signed in, Drive off | ✅ | ❌ |\n| Signed in, Drive on | ✅ | ✅ |\n\n### NetworkStatus Details\n\n```swift\n// Check network interface type\nswitch syncManager.networkStatus.connectivity {\ncase .connected(.wifi):\n    print(\"Connected via WiFi\")\ncase .connected(.cellular):\n    print(\"Connected via Cellular\")\ncase .connected(.wiredEthernet):\n    print(\"Connected via Ethernet\")\ncase .disconnected:\n    print(\"No network connection\")\ndefault:\n    break\n}\n\n// Check network conditions\nif syncManager.networkStatus.isConstrained {\n    print(\"Low Data Mode is enabled\")\n}\n\nif syncManager.networkStatus.isExpensive {\n    print(\"Using expensive connection (cellular/hotspot)\")\n}\n\nif syncManager.networkStatus.isLowPowerModeEnabled {\n    print(\"Low Power Mode is enabled\")\n}\n```\n\n### SyncEnvironmentStatus\n\n```swift\nlet status = syncManager.environmentStatus\n\n// Check if CloudKit sync is ready (network + account + not in low power mode)\nif status.isSyncReady {\n    // Safe to sync via CloudKit\n}\n\n// Check if iCloud Drive is ready (network + account + drive enabled + not in low power mode)\nif status.isCloudDriveReady {\n    // Safe to use iCloud Drive / Documents\n}\n\n// Check if suitable for large transfers (not constrained, not expensive)\nif status.isSuitableForLargeTransfer {\n    // Good for syncing large files\n}\n\n// Check if currently syncing\nif status.isSyncing {\n    // Sync in progress\n}\n```\n\n### Using AsyncStream\n\n```swift\n// Monitor network status changes\nTask {\n    for await status in syncManager.networkStatusStream {\n        print(\"Network changed: \\(status.isConnected)\")\n    }\n}\n\n// Monitor iCloud Drive availability changes\nTask {\n    for await available in syncManager.cloudDriveStatusStream {\n        print(\"iCloud Drive: \\(available ? \"enabled\" : \"disabled\")\")\n    }\n}\n\n// Monitor all status changes in one stream\nTask {\n    for await envStatus in syncManager.environmentStatusStream {\n        if envStatus.isSyncReady {\n            print(\"Ready to sync!\")\n        }\n    }\n}\n```\n\n### Wait Until Sync Ready\n\n```swift\n// Wait until sync conditions are met (with optional timeout)\nlet isReady = await syncManager.waitUntilSyncReady(timeout: .seconds(30))\nif isReady {\n    // Proceed with sync operation\n}\n```\n\n### Manual Status Check\n\n```swift\n// Manually refresh account status\nlet accountStatus = try await syncManager.checkAccountStatus()\n\n// Manually refresh network status\nlet networkStatus = syncManager.checkNetworkStatus()\n```\n\n### Handling Quota Exceeded\n\n```swift\nlet syncManager = SyncStatusAsyncManager(\n    monitoringOptions: .all,\n    cloudKitContainerID: \"iCloud.com.yourcompany.yourapp\",\n    quotaExceededHandler: {\n        // Notify the user about iCloud storage being full\n        print(\"iCloud storage is full!\")\n    }\n)\n```\n\n### Logging\n\n```swift\nlet syncManager = SyncStatusAsyncManager(\n    monitoringOptions: .all,\n    cloudKitContainerID: \"iCloud.com.yourcompany.yourapp\",\n    logger: YourLoggerInstance, // Conforming to LoggerManagerProtocol\n    showEventInLog: true\n)\n```\n\n### Testing Support\n\n```swift\n#if DEBUG\n// Create a manager for testing (no real monitoring)\nlet testManager = SyncStatusAsyncManager._forTesting()\n\n// Set states directly for testing\ntestManager._testSetNetworkStatus(NetworkStatus(\n    isConnected: true,\n    connectivity: .connected(.wifi),\n    isLowPowerModeEnabled: false,\n    isConstrained: false,\n    isExpensive: false\n))\ntestManager._testSetAccountStatus(.available)\ntestManager._testSetSyncEvent(.importing)\ntestManager._testSetCloudDriveAvailable(true)\n#endif\n```\n\n---\n\n## Legacy API (iOS 14+)\n\n### SyncStatusManager\n\nThe legacy API uses **Combine** and `@Published` for compatibility with older iOS versions.\n\n### Initialize SyncStatusManager\n\n```swift\n@StateObject var syncManager = SyncStatusManager()\n```\n\n### Basic Usage\n\n```swift\nstruct ContentView: View {\n    @StateObject var syncManager = SyncStatusManager()\n\n    var body: some View {\n        VStack {\n            Text(\"Sync Event: \\(syncManager.syncEvent)\")\n            \n            Button(\"Check iCloud Status\") {\n                Task {\n                    let status = await syncManager.validateICloudAvailability { status, error in\n                        print(\"Status: \\(status)\")\n                        if let error = error {\n                            print(\"Error: \\(error)\")\n                        }\n                    }\n                    if let status = status {\n                        print(\"iCloud Account Status: \\(status)\")\n                    }\n                }\n            }\n        }\n    }\n}\n```\n\n### Checking iCloud Availability\n\n```swift\nTask {\n    let status = await syncManager.validateICloudAvailability { status, error in\n        print(\"Account Status: \\(status)\")\n        if let error = error {\n            print(\"Error: \\(error.localizedDescription)\")\n        }\n    }\n    if status == .available {\n        // Proceed with synchronization\n    } else {\n        // Handle unavailable iCloud account\n    }\n}\n```\n\n### Handling Quota Exceeded\n\n```swift\nlet syncManager = SyncStatusManager(\n    quotaExceededHandler: {\n        // Notify the user about the quota issue\n    }\n)\n```\n\n---\n\n## API Comparison\n\n| Feature | `SyncStatusAsyncManager` | `SyncStatusManager` |\n|---------|--------------------------|---------------------|\n| Framework | Observation | Combine |\n| State Management | `@Observable` | `@Published` |\n| Network Monitoring | ✅ Detailed | ❌ Not included |\n| iCloud Drive Detection | ✅ Yes | ❌ No |\n| Selective Monitoring | ✅ MonitoringOptions | ❌ No |\n| Auto Account Monitoring | ✅ Automatic | ❌ Manual check |\n| AsyncStream Support | ✅ Yes | ❌ No |\n| iOS Minimum | 17.0 | 14.0 |\n| Swift Minimum | 6.2 | 6.0 |\n\n## License\n\nThis project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.\n\n## Acknowledgments\n\n- [General Findings About NSPersistentCloudKitContainer](https://crunchybagel.com/nspersistentcloudkitcontainer/)\n\n[![Buy Me A Coffee](https://cdn.buymeacoffee.com/buttons/v2/default-yellow.png)](https://buymeacoffee.com/fatbobman)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffatbobman%2Ficloudsyncstatuskit","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ffatbobman%2Ficloudsyncstatuskit","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffatbobman%2Ficloudsyncstatuskit/lists"}