| Packages/SharedPackage | ||
| SecureStorageSample | ||
| SecureStorageSample Watch App | ||
| SecureStorageSample Watch AppTests | ||
| SecureStorageSample Watch AppUITests | ||
| SecureStorageSample.xcodeproj | ||
| SecureStorageSample.xcworkspace | ||
| SecureStorageSampleTests | ||
| SecureStorageSampleUITests | ||
| .gitignore | ||
| README.md | ||
SecureStorageSample
A sample iOS app demonstrating the LocalData package capabilities for secure, typed storage across multiple domains.
Features
This app provides interactive demos for all LocalData storage options:
| Tab | Demo | Storage Domain |
|---|---|---|
| Defaults | Save/load/remove values | UserDefaults |
| Keychain | Secure credentials with biometrics | Keychain |
| Files | User profiles with Codable models | File System |
| Encrypted | Encrypted logs (AES or ChaCha20) | Encrypted File System |
| Sync | Platform availability & sync policies | Multiple |
The project also includes a watchOS companion app target for watch-specific demos.
Requirements
- iOS 17.0+
- watchOS 10.0+ (companion app target)
- Xcode 15+
Getting Started
- Open
SecureStorageSample.xcodeproj - Select an iOS simulator or device
- Build and run (⌘R)
- To use App Group demos, enable the App Group entitlement for each target that should share data. The identifier is derived from the bundle ID via SharedKit constants.
Project Structure
SharedPackage/
├── Package.swift
└── Sources/
└── SharedKit/
├── Constants/
│ ├── StorageKeyNames.swift
│ └── StorageServiceIdentifiers.swift
└── Models/
└── UserProfile.swift
SecureStorageSample/
├── ContentView.swift # Tabbed navigation
├── Models/
│ ├── Credential.swift
│ └── SampleLocationData.swift
├── StorageKeys/
│ ├── UserDefaults/
│ ├── Keychain/
│ ├── FileSystem/
│ ├── EncryptedFileSystem/
│ ├── AppGroup/
│ └── Platform/
├── WatchOptimized.swift # Watch data models
├── Services/
│ ├── AppStorageCatalog.swift
│ ├── ExternalKeyMaterialProvider.swift
│ └── WatchConnectivityService.swift
└── Views/
├── UserDefaultsDemo.swift
├── KeychainDemo.swift
├── FileSystemDemo.swift
├── EncryptedStorageDemo.swift
└── PlatformSyncDemo.swift
SecureStorageSample Watch App/
├── SecureStorageSampleApp.swift
├── ContentView.swift
├── Protocols/
│ └── WatchDataHandling.swift
├── State/
│ └── WatchProfileStore.swift
└── Services/
├── WatchConnectivityService.swift
└── Handlers/
└── UserProfileWatchHandler.swift
Storage Key Examples
The app demonstrates various storage configurations:
UserDefaults
- Simple string storage with automatic sync
- App Group UserDefaults support for shared preferences
Keychain
- 7 accessibility options (whenUnlocked, afterFirstUnlock, etc.)
- 6 access control options (biometry, passcode, etc.)
File System
- Documents: Permanent storage, backed up to iCloud. Use for critical user data.
- Caches: Purgeable storage (iOS may delete when low on space), not backed up. Use for temporary data.
- JSON and PropertyList serializers supported.
App Group Storage
- Shared UserDefaults via App Group identifier
- Shared files in the App Group container
- Requires App Group entitlements in all participating targets
Encrypted Storage
- AES-256-GCM or ChaCha20-Poly1305 encryption
- PBKDF2 or HKDF key derivation
- Complete file protection
- External key material example via
KeyMaterialProviding - Global encryption configuration (Keychain service/account) in app
init
Platform & Sync
- Platform availability (phoneOnly, watchOnly, all)
- Sync policies (never, manual, automaticSmall)
- Global sync configuration (max file size) in app
init
Global Configuration
The app demonstrates how to configure the LocalData library globally during startup in SecureStorageSampleApp.swift:
- Encryption: Customized Keychain service (
SecureStorageSample) and account (AppMasterKey) names to isolate the library's master encryption key from other apps. - Sync: Set a custom
maxAutoSyncSizeof 50KB to control which data is automatically synchronized to the Apple Watch, overriding the library's 100KB default. - File Storage: Scoping all library files into a
SecureStoragesub-directory. This ensures that the library's data (whether in the main sandbox or a shared App Group container) is kept neat and isolated within its own folder, rather than cluttering the root directories. - Storage Defaults: Pre-configuring the default Keychain service and App Group identifier. This allows common keys in the app to omit these identifiers, reducing boilerplate and making the code more maintainable.
This approach centralizes infrastructure settings and avoids hardcoding environment-specific values within individual storage keys.
Dependencies
- LocalData - Local package for typed secure storage
- SharedKit - Local package for shared iOS/watch models and constants
Notes
- Storage keys are now split into one file per key and grouped by domain; platform-focused keys live in
StorageKeys/Platformwith comments calling out availability/sync focus. - The shared model/constants live in
SharedPackage(SharedKit) to keep the watch/iOS data contract centralized. - Keychain service IDs and App Group identifiers are centralized in
SharedKit/Constants/StorageServiceIdentifiers.swiftto avoid hardcoded strings in keys. - The watch app uses a handler-based WatchConnectivity layer so new payload types can be added in
Services/Handlerswithout bloating the main service. - A
StorageKeyCatalogsample is included to generate a security audit report of all storage keys. - Each
StorageKeyincludes adescriptionused in audit reports. - The catalog is registered at app startup to enforce key registration and catch duplicates.
License
This sample is provided for demonstration purposes.