axiom-file-protection-ref

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

iOS File Protection Reference

iOS 文件保护参考文档

Purpose: Comprehensive reference for file encryption and data protection APIs Availability: iOS 4.0+ (all protection levels), latest enhancements in iOS 26 Context: Built on iOS Data Protection architecture using hardware encryption
用途:文件加密与数据保护API的综合参考文档 适用版本:iOS 4.0+(所有保护级别),iOS 26中新增最新增强功能 技术背景:基于iOS数据保护架构构建,采用硬件加密

When to Use This Skill

何时使用本技能

Use this skill when you need to:
  • Protect sensitive user data at rest
  • Choose appropriate FileProtectionType for files
  • Understand when files are accessible/encrypted
  • Debug "file not accessible" errors after device lock
  • Implement secure file storage
  • Compare Keychain vs file protection approaches
  • Handle background file access requirements
当你需要以下帮助时,可以使用本技能:
  • 保护静态状态下的敏感用户数据
  • 为文件选择合适的FileProtectionType
  • 了解文件何时可访问/处于加密状态
  • 调试设备锁定后出现的“文件无法访问”错误
  • 实现安全文件存储
  • 对比Keychain与文件保护的实现方案
  • 处理后台文件访问需求

Overview

概述

iOS Data Protection provides hardware-accelerated file encryption tied to the device passcode. When a user sets a passcode, every file can be encrypted with keys protected by that passcode.
Key concepts:
  • Files are encrypted automatically when protection is enabled
  • Encryption keys are derived from device hardware + user passcode
  • Files become inaccessible when device is locked (depending on protection level)
  • No performance cost (hardware AES encryption)

iOS数据保护提供硬件加速的文件加密,并与设备密码绑定。当用户设置密码后,所有文件都可使用该密码保护的密钥进行加密。
核心概念
  • 启用保护后,文件会被自动加密
  • 加密密钥由设备硬件+用户密码派生生成
  • 设备锁定时,文件将无法访问(具体取决于保护级别)
  • 无性能损耗(采用硬件AES加密)

Protection Levels Comparison

保护级别对比

LevelEncrypted UntilAccessible WhenUse ForBackground Access
completeDevice unlockedOnly while unlockedSensitive data (health, finances)❌ No
completeUnlessOpenFile closedAfter first unlock, while openLarge downloads, videos✅ If already open
completeUntilFirstUserAuthenticationFirst unlock after bootAfter first unlockMost app data✅ Yes
noneNeverAlwaysPublic caches, temp files✅ Yes
保护级别加密生效时段可访问时段适用场景后台访问权限
complete设备解锁前仅设备解锁时敏感数据(健康、财务信息)❌ 不支持
completeUnlessOpen文件关闭后首次解锁后,文件打开期间大文件下载、视频文件✅ 文件已打开时支持
completeUntilFirstUserAuthentication开机后首次解锁前首次解锁后大多数应用数据✅ 支持
none从不加密始终可访问公共缓存、临时文件✅ 支持

Detailed Level Descriptions

各保护级别详细说明

.complete

.complete

Full Description:
"The file is stored in an encrypted format on disk and cannot be read from or written to while the device is locked or booting."
Use For:
  • User health data
  • Financial information
  • Password vaults
  • Sensitive documents
  • Personal photos (if app requires maximum security)
Behavior:
  • Encrypted: ✅ Always
  • Accessible: Only when device unlocked
  • Background access: ❌ No (app can't read while locked)
  • Available after boot: ❌ No (until user unlocks)
Code Example:
swift
// ✅ CORRECT: Maximum security for sensitive data
func saveSensitiveData(_ data: Data, to url: URL) throws {
    try data.write(to: url, options: .completeFileProtection)
}

// Or set on existing file
try FileManager.default.setAttributes(
    [.protectionKey: FileProtectionType.complete],
    ofItemAtPath: url.path
)
Tradeoffs:
  • ✅ Maximum security
  • ❌ Can't access in background
  • ❌ User sees errors if app tries to access while locked
完整描述:
"文件以加密格式存储在磁盘上,设备锁定或开机过程中无法读取或写入。"
适用场景:
  • 用户健康数据
  • 财务信息
  • 密码管理器
  • 敏感文档
  • 个人照片(如果应用要求最高安全性)
行为特性:
  • 已加密: ✅ 始终加密
  • 可访问: 仅设备解锁时
  • 后台访问: ❌ 不支持(应用在设备锁定时无法读取)
  • 开机后可用: ❌ 不支持(需用户解锁后才可访问)
代码示例:
swift
// ✅ 正确用法:为敏感数据提供最高安全性
func saveSensitiveData(_ data: Data, to url: URL) throws {
    try data.write(to: url, options: .completeFileProtection)
}

// 或为已存在的文件设置保护
try FileManager.default.setAttributes(
    [.protectionKey: FileProtectionType.complete],
    ofItemAtPath: url.path
)
权衡取舍:
  • ✅ 最高安全性
  • ❌ 无法在后台访问
  • ❌ 如果应用在设备锁定时尝试访问,用户会看到错误提示

.completeUnlessOpen

.completeUnlessOpen

Full Description:
"The file is stored in an encrypted format on disk after it is closed."
Use For:
  • Large file downloads (continue in background)
  • Video files being played
  • Documents being edited
  • Any file that needs background access while open
Behavior:
  • Encrypted: ✅ When closed
  • Accessible: After first unlock, remains accessible while open
  • Background access: ✅ Yes (if file was already open)
  • Available after boot: ❌ No (until first unlock)
Code Example:
swift
// ✅ CORRECT: Download in background, but encrypted when closed
func startBackgroundDownload(url: URL, destination: URL) throws {
    try Data().write(to: destination, options: .completeFileProtectionUnlessOpen)

    // Open file handle for writing
    let fileHandle = try FileHandle(forWritingTo: destination)

    // Download continues in background
    // File remains accessible because it's open
    // When closed, file becomes encrypted

    // Later, when download complete:
    try fileHandle.close()  // Now encrypted until next unlock
}
Tradeoffs:
  • ✅ Good security (encrypted when not in use)
  • ✅ Background access (if already open)
  • ⚠️ Vulnerable while open
完整描述:
"文件关闭后以加密格式存储在磁盘上。"
适用场景:
  • 大文件下载(需在后台继续)
  • 正在播放的视频文件
  • 正在编辑的文档
  • 任何需要在打开期间支持后台访问的文件
行为特性:
  • 已加密: ✅ 文件关闭时加密
  • 可访问: 首次解锁后,文件打开期间保持可访问
  • 后台访问: ✅ 支持(如果文件已打开)
  • 开机后可用: ❌ 不支持(需首次解锁后)
代码示例:
swift
// ✅ 正确用法:后台下载,关闭后加密
func startBackgroundDownload(url: URL, destination: URL) throws {
    try Data().write(to: destination, options: .completeFileProtectionUnlessOpen)

    // 打开文件句柄用于写入
    let fileHandle = try FileHandle(forWritingTo: destination)

    // 下载在后台继续
    // 文件保持可访问状态,因为已打开
    // 关闭后,文件将被加密

    // 后续下载完成时:
    try fileHandle.close()  // 现在文件会被加密,直到下次解锁
}
权衡取舍:
  • ✅ 安全性良好(未使用时加密)
  • ✅ 支持后台访问(文件已打开时)
  • ⚠️ 文件打开期间存在安全风险

.completeUntilFirstUserAuthentication

.completeUntilFirstUserAuthentication

Full Description:
"The file is stored in an encrypted format on disk and cannot be accessed until after the device has booted."
Use For:
  • Most application data
  • User preferences
  • Downloaded content
  • Database files
  • Anything that needs background access
Behavior:
  • Encrypted: ✅ Always
  • Accessible: After first unlock following boot
  • Background access: ✅ Yes (after first unlock)
  • Available after boot: ❌ No (until user unlocks once)
This is the recommended default for most files.
Code Example:
swift
// ✅ CORRECT: Balanced security for most app data
func saveAppData(_ data: Data, to url: URL) throws {
    try data.write(
        to: url,
        options: .completeFileProtectionUntilFirstUserAuthentication
    )
}

// ✅ This file can be accessed in background after first unlock
func backgroundTaskCanAccessFile() {
    // This works even if device is locked (after first unlock)
    let data = try? Data(contentsOf: url)
}
Tradeoffs:
  • ✅ Protected during boot (device stolen while off)
  • ✅ Background access (normal operation)
  • ⚠️ Accessible while locked (less protection than .complete)
完整描述:
"文件以加密格式存储在磁盘上,设备开机后需完成首次用户验证才可访问。"
适用场景:
  • 大多数应用数据
  • 用户偏好设置
  • 下载内容
  • 数据库文件
  • 任何需要后台访问的内容
这是大多数文件推荐使用的默认保护级别。
行为特性:
  • 已加密: ✅ 始终加密
  • 可访问: 开机后首次解锁后
  • 后台访问: ✅ 支持(首次解锁后)
  • 开机后可用: ❌ 不支持(需用户首次解锁后)
代码示例:
swift
// ✅ 正确用法:为大多数应用数据提供平衡的安全性
func saveAppData(_ data: Data, to url: URL) throws {
    try data.write(
        to: url,
        options: .completeFileProtectionUntilFirstUserAuthentication
    )
}

// ✅ 首次解锁后,即使设备锁定也可在后台访问文件
func backgroundTaskCanAccessFile() {
    // 即使设备锁定(首次解锁后),此操作也能正常执行
    let data = try? Data(contentsOf: url)
}
权衡取舍:
  • ✅ 开机期间受保护(设备关机时被盗可避免数据泄露)
  • ✅ 正常运行时支持后台访问
  • ⚠️ 设备锁定时仍可访问(安全性低于.complete级别)

.none

.none

Full Description:
"The file has no special protections associated with it."
Use For:
  • Public cache data
  • Temporary files
  • Non-sensitive downloads
  • Thumbnails
  • Only when absolutely necessary
Behavior:
  • Encrypted: ❌ Never
  • Accessible: ✅ Always
  • Background access: ✅ Always
  • Available after boot: ✅ Always
Code Example:
swift
// ⚠️ USE SPARINGLY: Only for truly non-sensitive data
func cachePublicThumbnail(_ data: Data, to url: URL) throws {
    try data.write(to: url, options: .noFileProtection)
}
Tradeoffs:
  • ✅ Always accessible
  • ❌ No encryption
  • ❌ Vulnerable if device is stolen

完整描述:
"文件无任何特殊保护。"
适用场景:
  • 公共缓存数据
  • 临时文件
  • 非敏感下载内容
  • 缩略图
  • 仅在绝对必要时使用
行为特性:
  • 已加密: ❌ 从不加密
  • 可访问: ✅ 始终可访问
  • 后台访问: ✅ 始终支持
  • 开机后可用: ✅ 始终可用
代码示例:
swift
// ⚠️ 谨慎使用:仅适用于完全非敏感数据
func cachePublicThumbnail(_ data: Data, to url: URL) throws {
    try data.write(to: url, options: .noFileProtection)
}
权衡取舍:
  • ✅ 始终可访问
  • ❌ 无加密保护
  • ❌ 设备被盗时数据易泄露

Setting File Protection

设置文件保护

At File Creation

文件创建时设置

swift
// ✅ RECOMMENDED: Set protection when writing
let sensitiveData = userData.jsonData()
try sensitiveData.write(
    to: fileURL,
    options: .completeFileProtection
)
swift
// ✅ 推荐用法:写入时设置保护级别
let sensitiveData = userData.jsonData()
try sensitiveData.write(
    to: fileURL,
    options: .completeFileProtection
)

On Existing Files

为已存在的文件设置

swift
// ✅ CORRECT: Change protection on existing file
try FileManager.default.setAttributes(
    [.protectionKey: FileProtectionType.complete],
    ofItemAtPath: fileURL.path
)
swift
// ✅ 正确用法:修改已存在文件的保护级别
try FileManager.default.setAttributes(
    [.protectionKey: FileProtectionType.complete],
    ofItemAtPath: fileURL.path
)

Default Protection for Directory

为目录设置默认保护级别

swift
// ✅ CORRECT: Set default protection for directory
// New files inherit this protection
try FileManager.default.setAttributes(
    [.protectionKey: FileProtectionType.completeUntilFirstUserAuthentication],
    ofItemAtPath: directoryURL.path
)
swift
// ✅ 正确用法:为目录设置默认保护级别
// 目录下的新文件将继承此保护级别
try FileManager.default.setAttributes(
    [.protectionKey: FileProtectionType.completeUntilFirstUserAuthentication],
    ofItemAtPath: directoryURL.path
)

Checking Current Protection

检查当前保护级别

swift
// ✅ Check file's current protection level
func checkFileProtection(at url: URL) throws -> FileProtectionType? {
    let attributes = try FileManager.default.attributesOfItem(atPath: url.path)
    return attributes[.protectionKey] as? FileProtectionType
}

// Usage
if let protection = try? checkFileProtection(at: fileURL) {
    switch protection {
    case .complete:
        print("Maximum protection")
    case .completeUntilFirstUserAuthentication:
        print("Standard protection")
    default:
        print("Other protection")
    }
}

swift
// ✅ 检查文件当前的保护级别
func checkFileProtection(at url: URL) throws -> FileProtectionType? {
    let attributes = try FileManager.default.attributesOfItem(atPath: url.path)
    return attributes[.protectionKey] as? FileProtectionType
}

// 使用示例
if let protection = try? checkFileProtection(at: fileURL) {
    switch protection {
    case .complete:
        print("Maximum protection")
    case .completeUntilFirstUserAuthentication:
        print("Standard protection")
    default:
        print("Other protection")
    }
}

File Protection vs Keychain

文件保护 vs Keychain

Decision Matrix

决策矩阵

Use CaseRecommendedWhy
Passwords, tokens, keysKeychainDesigned for small secrets
Small sensitive values (<few KB)KeychainMore secure, encrypted separately
Files >1 KBFile ProtectionKeychain not designed for large data
User documentsFile ProtectionNatural file-based storage
Structured secretsKeychainQuery by key, access control
应用场景推荐方案原因
密码、令牌、密钥Keychain专为小型机密数据设计
小型敏感数据(<几KB)Keychain安全性更高,单独加密
大于1KB的文件文件保护Keychain并非为大型数据设计
用户文档文件保护符合基于文件的自然存储方式
结构化机密数据Keychain支持按密钥查询、访问控制

Code Comparison

代码对比

swift
// ✅ CORRECT: Small secrets in Keychain
let passwordData = password.data(using: .utf8)!
let query: [String: Any] = [
    kSecClass as String: kSecClassGenericPassword,
    kSecAttrAccount as String: "userPassword",
    kSecValueData as String: passwordData,
    kSecAttrAccessible as String: kSecAttrAccessibleWhenUnlocked
]
SecItemAdd(query as CFDictionary, nil)

// ✅ CORRECT: Files with file protection
let userData = try JSONEncoder().encode(user)
try userData.write(to: fileURL, options: .completeFileProtection)
Keychain advantages:
  • More granular access control (Face ID/Touch ID)
  • Separate encryption (not tied to file system)
  • Survives app deletion (if configured)
File protection advantages:
  • Works with existing file operations
  • Handles large data efficiently
  • Automatic with minimal code

swift
// ✅ 正确用法:小型机密数据存储在Keychain中
let passwordData = password.data(using: .utf8)!
let query: [String: Any] = [
    kSecClass as String: kSecClassGenericPassword,
    kSecAttrAccount as String: "userPassword",
    kSecValueData as String: passwordData,
    kSecAttrAccessible as String: kSecAttrAccessibleWhenUnlocked
]
SecItemAdd(query as CFDictionary, nil)

// ✅ 正确用法:文件使用文件保护机制
let userData = try JSONEncoder().encode(user)
try userData.write(to: fileURL, options: .completeFileProtection)
Keychain优势:
  • 更精细的访问控制(Face ID/Touch ID)
  • 独立加密(不与文件系统绑定)
  • 可在应用删除后保留数据(需配置)
文件保护优势:
  • 可与现有文件操作兼容
  • 高效处理大型数据
  • 自动生效,所需代码极少

Background Access Considerations

后台访问注意事项

iOS Background Modes and File Protection

iOS后台模式与文件保护

swift
// ❌ WRONG: .complete files can't be accessed in background
class BackgroundTask {
    func performBackgroundSync() {
        // This FAILS if file has .complete protection and device is locked
        let data = try? Data(contentsOf: sensitiveFileURL)
        // data will be nil if device locked
    }
}

// ✅ CORRECT: Use .completeUntilFirstUserAuthentication
// Files accessible in background after first unlock
try data.write(
    to: fileURL,
    options: .completeFileProtectionUntilFirstUserAuthentication
)
swift
// ❌ 错误用法:.complete级别的文件无法在后台访问
class BackgroundTask {
    func performBackgroundSync() {
        // 如果文件使用.complete保护级别且设备锁定,此操作会失败
        let data = try? Data(contentsOf: sensitiveFileURL)
        // 设备锁定时data为nil
    }
}

// ✅ 正确用法:使用.completeUntilFirstUserAuthentication
// 首次解锁后,即使设备锁定也可在后台访问文件
try data.write(
    to: fileURL,
    options: .completeFileProtectionUntilFirstUserAuthentication
)

Handling Protection Errors

处理保护相关错误

swift
// ✅ CORRECT: Handle protection errors gracefully
func readFile(at url: URL) -> Data? {
    do {
        return try Data(contentsOf: url)
    } catch let error as NSError {
        if error.domain == NSCocoaErrorDomain &&
           error.code == NSFileReadNoPermissionError {
            // File is protected and device is locked
            print("File protected, device locked")
            return nil
        }
        throw error
    }
}

swift
// ✅ 正确用法:优雅处理保护相关错误
func readFile(at url: URL) -> Data? {
    do {
        return try Data(contentsOf: url)
    } catch let error as NSError {
        if error.domain == NSCocoaErrorDomain &&
           error.code == NSFileReadNoPermissionError {
            // 文件受保护且设备已锁定
            print("File protected, device locked")
            return nil
        }
        throw error
    }
}

iCloud and File Protection

iCloud与文件保护

How Protection Works with iCloud

保护机制在iCloud中的工作方式

Local file protection:
  • Applied to local cached copies
  • Does NOT affect iCloud-stored versions
  • iCloud has its own encryption (in transit and at rest)
iCloud encryption:
  • All iCloud data encrypted at rest (Apple-managed keys)
  • End-to-end encryption available for some data types (Advanced Data Protection)
  • File protection only affects local device
swift
// ✅ CORRECT: Protection on iCloud file affects local copy only
func saveToICloud(data: Data, filename: String) throws {
    guard let iCloudURL = FileManager.default.url(
        forUbiquityContainerIdentifier: nil
    ) else { return }

    let fileURL = iCloudURL.appendingPathComponent(filename)

    // This protection applies to local cached copy
    try data.write(to: fileURL, options: .completeFileProtection)

    // iCloud has separate encryption for cloud storage
}

本地文件保护:
  • 仅应用于本地缓存副本
  • 不影响iCloud存储的版本
  • iCloud有自身的加密机制(传输中和静态存储时)
iCloud加密:
  • 所有iCloud数据静态存储时均加密(由Apple管理密钥)
  • 部分数据类型支持端到端加密(高级数据保护)
  • 文件保护仅影响本地设备
swift
// ✅ 正确用法:iCloud文件的保护仅影响本地副本
func saveToICloud(data: Data, filename: String) throws {
    guard let iCloudURL = FileManager.default.url(
        forUbiquityContainerIdentifier: nil
    ) else { return }

    let fileURL = iCloudURL.appendingPathComponent(filename)

    // 此保护级别仅应用于本地缓存副本
    try data.write(to: fileURL, options: .completeFileProtection)

    // iCloud云存储有独立的加密机制
}

Common Patterns

常见实现模式

Pattern 1: Default Protection for New Apps

模式1:新应用的默认保护设置

swift
// ✅ RECOMMENDED: Set default protection at app launch
func configureDefaultFileProtection() {
    let fileManager = FileManager.default

    let directories: [FileManager.SearchPathDirectory] = [
        .documentDirectory,
        .applicationSupportDirectory
    ]

    for directory in directories {
        guard let url = fileManager.urls(
            for: directory,
            in: .userDomainMask
        ).first else { continue }

        try? fileManager.setAttributes(
            [.protectionKey: FileProtectionType.completeUntilFirstUserAuthentication],
            ofItemAtPath: url.path
        )
    }
}

// Call during app initialization
func application(_ application: UIApplication, didFinishLaunchingWithOptions...) {
    configureDefaultFileProtection()
    return true
}
swift
// ✅ 推荐用法:应用启动时设置默认保护级别
func configureDefaultFileProtection() {
    let fileManager = FileManager.default

    let directories: [FileManager.SearchPathDirectory] = [
        .documentDirectory,
        .applicationSupportDirectory
    ]

    for directory in directories {
        guard let url = fileManager.urls(
            for: directory,
            in: .userDomainMask
        ).first else { continue }

        try? fileManager.setAttributes(
            [.protectionKey: FileProtectionType.completeUntilFirstUserAuthentication],
            ofItemAtPath: url.path
        )
    }
}

// 应用初始化时调用
func application(_ application: UIApplication, didFinishLaunchingWithOptions...) {
    configureDefaultFileProtection()
    return true
}

Pattern 2: Encrypting Database Files

模式2:加密数据库文件

swift
// ✅ CORRECT: Protect SwiftData/SQLite database
let appSupportURL = FileManager.default.urls(
    for: .applicationSupportDirectory,
    in: .userDomainMask
)[0]

let databaseURL = appSupportURL.appendingPathComponent("app.sqlite")

// Set protection before creating database
try? FileManager.default.setAttributes(
    [.protectionKey: FileProtectionType.completeUntilFirstUserAuthentication],
    ofItemAtPath: appSupportURL.path
)

// Now create database - it inherits protection
let container = try ModelContainer(
    for: MyModel.self,
    configurations: ModelConfiguration(url: databaseURL)
)
swift
// ✅ 正确用法:保护SwiftData/SQLite数据库
let appSupportURL = FileManager.default.urls(
    for: .applicationSupportDirectory,
    in: .userDomainMask
)[0]

let databaseURL = appSupportURL.appendingPathComponent("app.sqlite")

// 创建数据库前设置保护级别
try? FileManager.default.setAttributes(
    [.protectionKey: FileProtectionType.completeUntilFirstUserAuthentication],
    ofItemAtPath: appSupportURL.path
)

// 现在创建数据库 - 它将继承保护级别
let container = try ModelContainer(
    for: MyModel.self,
    configurations: ModelConfiguration(url: databaseURL)
)

Pattern 3: Downgrading Protection for Background Tasks

模式3:为后台任务降低保护级别

swift
// ⚠️ SOMETIMES NECESSARY: Lower protection for background access
func enableBackgroundAccess(for url: URL) throws {
    try FileManager.default.setAttributes(
        [.protectionKey: FileProtectionType.completeUntilFirstUserAuthentication],
        ofItemAtPath: url.path
    )
}

// Only do this if:
// 1. Background access is truly required
// 2. Data sensitivity allows it
// 3. You've considered security tradeoffs

swift
// ⚠️ 仅在必要时使用:为后台访问降低保护级别
func enableBackgroundAccess(for url: URL) throws {
    try FileManager.default.setAttributes(
        [.protectionKey: FileProtectionType.completeUntilFirstUserAuthentication],
        ofItemAtPath: url.path
    )
}

// 仅在以下情况时使用:
// 1. 确实需要后台访问权限
// 2. 数据敏感度允许降低保护级别
// 3. 已充分考虑安全性权衡

Debugging File Protection Issues

调试文件保护问题

Issue: File Not Accessible in Background

问题:后台无法访问文件

Symptom: Background tasks fail to read files
swift
// Debug: Check current protection
if let protection = try? FileManager.default.attributesOfItem(
    atPath: url.path
)[.protectionKey] as? FileProtectionType {
    print("Protection: \(protection)")
    if protection == .complete {
        print("❌ Can't access in background when locked")
    }
}
Solution: Use
.completeUntilFirstUserAuthentication
instead
症状:后台任务读取文件失败
swift
// 调试:检查当前保护级别
if let protection = try? FileManager.default.attributesOfItem(
    atPath: url.path
)[.protectionKey] as? FileProtectionType {
    print("Protection: \\(protection)")
    if protection == .complete {
        print("❌ 设备锁定时无法在后台访问")
    }
}
解决方案:改用
.completeUntilFirstUserAuthentication
保护级别

Issue: Files Inaccessible After Restart

问题:重启后文件无法访问

Symptom: App can't access files immediately after device reboot
Cause: Using
.complete
or
.completeUntilFirstUserAuthentication
(works as designed)
Solution: This is expected behavior. Either:
  1. Wait for user to unlock device
  2. Handle gracefully with appropriate UI
  3. Use
    .none
    for files that must be accessible (security tradeoff)

症状:设备重启后应用立即无法访问文件
原因:使用了
.complete
.completeUntilFirstUserAuthentication
保护级别(属于设计预期行为)
解决方案:此为预期行为,可选择以下方式处理:
  1. 等待用户解锁设备
  2. 通过合适的UI优雅提示用户
  3. 为必须可访问的文件使用
    .none
    保护级别(需权衡安全性)

Entitlements

权限配置

File protection generally works without special entitlements, but some features require:
文件保护通常无需特殊权限,但部分功能需要:

Data Protection Entitlement

数据保护权限

xml
<!-- Required for: .complete protection level -->
<key>com.apple.developer.default-data-protection</key>
<string>NSFileProtectionComplete</string>
When needed:
  • Using
    .complete
    protection
  • Some iOS versions for any protection (check documentation)
How to add:
  1. Xcode → Target → Signing & Capabilities
  2. "+ Capability" → Data Protection
  3. Select protection level

xml
<!-- 适用场景:使用.complete保护级别时需要 -->
<key>com.apple.developer.default-data-protection</key>
<string>NSFileProtectionComplete</string>
需要配置的情况:
  • 使用
    .complete
    保护级别
  • 部分iOS版本中使用任何保护级别(请查阅官方文档)
添加方式:
  1. Xcode → 目标项目 → 签名与功能
  2. "+ Capability" → 数据保护
  3. 选择保护级别

Quick Reference Table

快速参考表

ScenarioRecommended ProtectionAccessible When Locked?Background Access?
User health data
.complete
❌ No❌ No
Financial records
.complete
❌ No❌ No
Most app data
.completeUntilFirstUserAuthentication
✅ Yes (after first unlock)✅ Yes
Downloads (large files)
.completeUnlessOpen
✅ While open✅ While open
Database files
.completeUntilFirstUserAuthentication
✅ Yes✅ Yes
Downloaded images
.completeUntilFirstUserAuthentication
✅ Yes✅ Yes
Public caches
.none
✅ Yes✅ Yes
Temp files
.none
✅ Yes✅ Yes

场景推荐保护级别设备锁定时可访问?后台访问?
用户健康数据
.complete
❌ 否❌ 否
财务记录
.complete
❌ 否❌ 否
大多数应用数据
.completeUntilFirstUserAuthentication
✅ 是(首次解锁后)✅ 是
大文件下载
.completeUnlessOpen
✅ 文件打开时是✅ 文件打开时是
数据库文件
.completeUntilFirstUserAuthentication
✅ 是✅ 是
下载的图片
.completeUntilFirstUserAuthentication
✅ 是✅ 是
公共缓存
.none
✅ 是✅ 是
临时文件
.none
✅ 是✅ 是

Related Skills

相关技能

  • axiom-storage
    — Decide when to use file protection vs other security measures
  • axiom-storage-management-ref
    — File lifecycle, purging, and disk management
  • axiom-storage-diag
    — Debug file access issues

Last Updated: 2025-12-12 Skill Type: Reference Minimum iOS: 4.0 (all protection levels) Latest Updates: iOS 26
  • axiom-storage
    — 决定何时使用文件保护或其他安全措施
  • axiom-storage-management-ref
    — 文件生命周期、清理与磁盘管理
  • axiom-storage-diag
    — 调试文件访问问题

最后更新时间: 2025-12-12 技能类型: 参考文档 最低iOS版本: 4.0(所有保护级别) 最新更新: iOS 26",