ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

ZipArchive 助力 iOS 加密 RAR 文件解压与创建实践指南

ZipArchive 助力 iOS 加密 RAR 文件解压与创建实践指南 简介这是iOS开发中常用的压缩解压库ZipArchive的新版源码在保留ZIP处理能力的基础上新增了加密RAR文件的创建与解压支持解决了普通ZipArchive无法处理受密码保护RAR文件的问题面向需要实现文件打包、安全归档和下载后解密的iOS开发者。压缩包共12个文件包括6个.h头文件用于暴露接口、4个.c实现文件提供底层逻辑、1个.mm文件衔接Objective-C与C代码以及1个readme.txt说明文档整体只有39KB结构紧凑便于查看接口声明与具体实现之间的对应关系。已有208人学习下载适合正在做iOS文件管理功能、希望扩展压缩格式支持的中初级开发者学习参考。通过阅读源码可以理解ZIP与RAR操作中API参数、密码校验、错误处理等实现思路掌握创建加密归档和解压受保护文件的核心方法同时minizip相关模块展示了底层压缩逻辑的集成方式而这些能力可直接用于数据备份、更新包管理、用户文件分享等场景为二次开发或学习研究提供清晰的代码基础。1. 新版 ZipArchive 把加密 rar 变成 iOS 的一等公民iOS 文件 App 与UIDocumentInteractionController对 zip 开箱即用但面对 .rar 附件基本只能「收到但打不开」。更隐蔽的是加密 rar如果压缩时勾了文件名加密连目录列表都拿不到必须先输入密码才能看到里面有什么。新版 ZipArchive 在源码包里补充的正是创建与解压加密 rar 这条链路把原本要自己桥接 C unrar 的脏活收敛到一组与 zip 对称的接口上。这篇文章按「格式差异 → 集成 → 解压 → 创建 → 验证」展开适合做网盘备份、企业文件分发、邮件代理类 App 的 iOS 开发者尤其是需要把 rar 支持放进沙盒又不想重写解码器的团队。2. 加密 rar 的格式底牌RAR4、RAR5 与 ZipArchive 的底层选择2.1 RAR4 与 RAR5 的加密差异决定了 API 怎么设计rar 不像 zip 那样有开放的 zlib 规范格式与压缩算法长期由 RARLAB 维护分为 RAR4 与 RAR5 两代互不兼容。解压加密文件时真正影响代码路径的不是 AES 算法本身而是「文件名是否也被加密」以及「密钥怎么派生」。RAR5 的密钥派生使用 PBKDF2-HMAC-SHA256迭代次数随存档写入RAR4 则使用其自有迭代逻辑因此在RARSetPassword之后RAR5 存档要等待 PBKDF2 计算完成耗时明显长于 RAR4这是 UI 上「卡一下」的常见来源。对比项RAR4经典格式RAR5新版格式加密算法AES-128AES-256 CBC密钥派生自有迭代逻辑参数固定PBKDF2-HMAC-SHA256迭代次数写入存档文件头加密支持早期工具兼容差支持行为更稳定文件名编码本地代码页 可选 UTF-8强制 UTF-8分卷命名.rar .r00、.r01 递增.part1.rar、.part2.rar4GB 以上文件受 32 位字段限制原生支持这张表解释了用户侧一个长期困惑为什么有些 rar 不输密码也能看到文件名有些连文件名都列不出。区别在于压缩时是否选择了「加密文件名」。当文件名被加密ar 的头部本身就是密文必须在读头部之前把密码传给RARSetPassword否则目录接口返回的数量和实际不符。新版 ZipArchive 在列目录接口上应该同时处理这两种状态密码为空时先尝试无密码列目录失败后再提示输入密码而不是直接把错误抛给调用方。2.2 ZipArchive 集成 unrar 的剖面桥接层与最小编译验证拿到标题里这种源码包后解压出来通常是一个包含zip与rar两个功能平面的完整工程。rar 这一侧几乎不可能由 ZipArchive 自研业界通用做法是把 RARLAB 官方 unrar SDK 编译进 iOS 工程。unrar 主体是 CSwift 无法直接调用所以至少要有一个.mm桥接文件把RAROpenArchiveEx、RARSetPassword、RARReadHeaderEx、RARProcessFile这一组 C 接口包成 Objective-C 类再暴露给 Swift。// RARUnrarAdapter.mm 的关键调用时序伪码按实际头文件初始化 openData RAROpenArchiveDataEx openData {0}; openData.ArcName rarPath.UTF8String; openData.OpenMode RAR_OM_EXTRACT; HANDLE rarH RAROpenArchiveEx(openData); RARSetPassword(rarH, password.UTF8String); while (RARReadHeaderEx(rarH, header) 0) { RARProcessFile(rarH, RAR_EXTRACT, NULL, NULL); // header.Name 此时已解开RAR5 下以 UTF-8 形式给出 } RARCloseArchive(rarH);逻辑说明顺序是固定的先RAROpenArchiveEx拿到句柄再RARSetPassword注入密码然后循环RARReadHeaderEx与RARProcessFile。RARProcessFile的第二个参数是操作类型RAR_EXTRACT落盘RAR_TEST只校验不解压调试阶段先用RAR_TEST可以避免把坏文件写进沙盒。如果RAROpenArchiveEx返回时openData.OpenResult非零最常见原因是文件路径不存在或密码参数为空先检查这两处再往上追。如果工程用 CocoaPods 管理集成命令里有一个值得注意的坑use_frameworks! pod ZipArchive, :git https://github.com/ZipArchive/ZipArchive.git, :branch masteruse_frameworks!保证 Swift 的import ZipArchive能直接访问模块:branch master是追新写法生产环境建议固定到一个 tag。首次编译如果报Unrar/version.hpp找不到通常是 Pods 缓存残留执行pod deintegrate再重新pod install就能恢复。手动拖拽源码时unrar 目录里所有.cpp与.hpp都要加入编译目标漏掉archive.cpp会在链接阶段出现大量未定义符号而且符号以 C mangled 形式存在排查时不容易直接定位。2.3 为什么不自研 rar 解码器rar 的压缩算法没有开放规范开源社区中的实现大多只能覆盖 RAR4且对加密头、分卷、大文件的支持参差不齐。对加密场景解码器一旦在字节序或密钥派生上判断错误结果不是「报错退出」而是「把错误文件当成正常文件写出」这种静默损坏在备份类产品里是不可接受的。所以行业默认路径是接官方 unrar 源码ZipArchive 新版扩展 rar 支持时同样走这条路通过桥接层把复杂度隔离在 OC 边界内上层 Swift 感知不到 C 的存在。3. 用 ZipArchive 解压加密 rar密码、进度与乱码名的一次性解决3.1 带密码解压的最小实现新版源码包的 rar 能力通常以桥接层形式暴露网上可参考的现成实现与 UnrarKit 的 API 风格接近接口语义对应第二节的 C 调用时序。以这个风格写的解压函数可以直接跑import ZipArchive import UnrarKit // 若源码包内置桥接可替换为 ZipArchive 的 rar 扩展头 func extractEncryptedRAR(from url: URL, to dest: URL, password: String) throws { // 1. 建立带密码的归档句柄内部完成 RAROpenArchive RARSetPassword let archive try URKArchive(url: url, password: password) // 2. 列目录。加密文件名时这一步会先用密码解开文件头 try archive.listFiles { entry in print(entry: \(entry)) } // 3. 正式解压内部按块循环 RARProcessFileprogress 回调驱动 UI try archive.extractFiles(to: dest, overwrite: true) { info in print(解压进度: \(info)) } }逻辑说明第一段构造 archive 并不真正读文件只有listFiles或extractFiles被调用时才打开句柄listFiles放在解压前的作用是提前暴露密码错误。若密码错误这个库会在列目录阶段抛错而不是让用户等到解压中途才看到失败交互上友好很多。extractFiles的 progress 回调从底层 unrar 的 callback 逐块透传可以用来驱动进度条。参数说明url必须是文件 URL没必要先把 rar 读成Data流式解压对 2GB 以上的包尤为重要password传普通字符串即可RAR5 存档内部按 UTF-8 参与 PBKDF2OC 桥接层会把password.UTF8String直接交给RARSetPassword所以不要在这个参数上做 Base64 之类加工overwrite: true表示覆盖目标目录中的同名文件如果你要保留原始文件改成false并自行处理FileManager冲突。dest目录建议提前用createDirectory(withIntermediateDirectories: true)建好否则部分实现会失败。3.2 密码错误识别与 Keychain 落盘「记住密码」是加密 rar 场景里的刚需但不要用UserDefaults存解压密码。常见做法是解压成功后把密码写入 Keychain以 rar 文件路径的 SHA-256 作为 key下次打开时先查 Keychain命中了就不弹密码框。func remember(_ password: String, for filePath: String) { let key SHA256.hex(filePath) // 路径哈希作为 Keychain account SecItemDelete([ kSecClass as String: kSecClassGenericPassword, kSecAttrAccount as String: key ] as CFDictionary) SecItemAdd([ kSecClass as String: kSecClassGenericPassword, kSecAttrAccount as String: key, kSecValueData as String: password.data(using: .utf8)! ] as CFDictionary, nil) }参数说明kSecAttrAccount用路径哈希而不是原始路径避免目录迁移时 key 冲突kSecValueData必须转成Data字符串直接传会导致保存失败。Keychain 的SecItemAdd要求主线程调用在后台 GCD 队列里调用会偶发errSecMissingEntitlement很多团队第一次接入时都会踩这个。取出密码时用SecItemCopyMatching把kSecReturnData设为true取回后String(data:encoding: .utf8)还原。提示不要把解压密码写进日志。unrar 的 C 层在密码错误时会把错误码返回给桥接层但不少桥接实现会把密码一并拼进 NSError 的 userInfo线上日志一旦输出这个字典等于明文泄漏。3.3 文件名乱码RAR4 时代的代码页遗留rar 文件名乱码几乎都出在 RAR4 存档上。RAR4 的文件名编码与压缩端的系统代码页绑定中文环境下生成的包在 macOS 或 iOS 上可能被解成乱码。RAR5 强制 UTF-8基本没有这个问题所以碰到乱码先确认格式版本再用RARReadHeaderEx返回的header.Name做判断如果能按 UTF-8 转NSString直接使用转换失败时可尝试按 GBK 的 DOS 变体kCFStringEncodingDOSChineseSimplif解码一次这是处理历史中文压缩包最实用的补偿手段。改文件名不要在解压循环内打断RARProcessFile。正确做法是先完整解压到临时目录再遍历FileManager枚举出的文件对乱码路径执行moveItem。原因是 unrar 按原始名称写文件循环中修改输出名需要切换RARProcessFile的ArcName参数影响解压中断时的恢复逻辑代价大于先解后改。4. 创建加密 rar 的可执行路径服务端命令与客户端 zip 兜底4.1 创建 rar 为什么无法靠源码包白嫖这是标题里最需要较真的点unrar 库只负责解压rar 的压缩算法没有开放实现开源生态里找不到可用的 RAR5 编码器。iOS 进程内创建加密 rar唯一合规路径是持有 RARLAB 商业授权并在工程里链接其编译好的静态库如果在源码包里看到一个 rar 可执行文件想用NSTask调可以放弃——iOS 沙盒不允许 fork/exec 子进程。所以拿到「新增创建加密 rar」的源码包时第一件事应该是检查它内置的到底是 unrar 解压库还是完整的商业 SDK。很多下载站资源只做到解压侧创建侧由其配套的 macOS 工具代劳移动端 APP 并没有真正的创建方法。这个边界直接决定了项目排期如果产品必须在 APP 内生成加密 rar就不要指望纯客户端把生成逻辑放到服务端是省时省力的选择。4.2 服务端生成加密 rar 的最小命令服务端跑 Linux 或 macOS安装官方 rar 命令行工具后一条命令就能产出 RAR5 AES-256 隐藏文件名的加密 rarrar a -m5 -ma5 -hpPssw0rd-2024 /srv/backup.rar /srv/export/逻辑说明a是添加模式把/srv/export/目录整体写入/srv/backup.rar。-ma5强制 RAR5 容器-hp是加密文件名并同时加密文件头比小写-p多一个隐藏目录列表的效果。客户端收到这种包后不输密码连文件名都看不到正好对应第 3 章列目录前需要RARSetPassword的场景。参数说明-m5是最高压缩等级耗时最长备份场景按文件类型取舍视频素材用-m1反而更快需要分卷时追加-v1g表示每卷 1GB生成的文件名像backup.part1.rar、backup.part2.rar客户端需要把这些分卷放在同一目录才能完整解压。长度与复杂度都达标的密码在这个场景里不是可选项而是必要条件。客户端侧如果平台有限制临时用 zip 兜底是完全可行的ZipArchive 创建 zip 的接口是确定可用的try SSZipArchive.createZipFile( atPath: zipPath, withContentsOfDirectory: srcDir, keepParentDirectory: true, compressionLevel: .best, password: Pssw0rd-2024 )逻辑说明withContentsOfDirectory会递归整个目录keepParentDirectory: true把目录本身也放进压缩包解压时多一层壳password非 nil 时对 zip 使用 AES-256 加密同样能隐藏文件名。这个方案适合企业内部交换文件缺点是需要接收方认 zip 加密格式老版本解压工具可能只支持 ZipCrypto 而拒绝 AES 条目给外部用户时优先选 rar 或直接明示压缩工具版本。4.3 分卷、后台任务与压缩时机的选择加密压缩的耗时来自两个方向压缩算法本身与 PBKDF2 密钥派生。RAR5 创建时迭代次数写进存档客户端解压时要重算一遍所以服务端生成策略里不要把迭代参数拉满兼顾兼容性和性能的默认值即可。分卷在服务端用-v控制客户端解压分卷包时保证所有分卷在同一目录且命名完整unrar 会自动按序读取。服务端生成为主体的架构里客户端只需要在下载完成后用第 3 章的解压链路处理压缩时机放到用户闲时的服务端队列。如果产品坚持客户端生成非 rar 的加密包zip 方向用SSZipArchive.createZipFile加密码参数就能落地。压缩操作要放到后台任务里执行避免被系统挂起。5. 验收加密 rar 的三个动作命令行校验、故障对照与密码强度5.1 用 macOS 命令行做一轮闭环验收把 App 沙盒 Documents 里生成或下载的 rar 通过文件共享拖到 Mac 上不需要依赖 iOS 开发者模式直接在终端校验最快。macOS 默认没有 unrar 命令brew install unrar装好之后两个命令足够用# 带密码列出文件密码紧跟 -p不要留空格 unrar l -pPssw0rd-2024 backup.rar # 完整测试逐字节校验 CRC unrar t -pPssw0rd-2024 backup.rarunrar t输出里每个文件都出现CRC OK才能判定这个加密 rar 在工具链层面完整可读。iOS 端的闭环验证可以再进一步解压后用FileManager读出同一个文件的字节在 Mac 上shasum -a 256对比原始文件两边哈希一致才算真正通过。5.2 三个高频故障的判别法故障现象典型原因排查动作列目录返回空列表文件头加密且密码错误用unrar l手动输入错误密码复现确认是密码层问题若unrar l正常而 App 报错检查桥接层是否漏调RARSetPassword解压到一半退出单一分卷或文件数据损坏用unrar t定位到具体损坏文件分卷包先检查所有.partN.rar是否齐全文件名乱码RAR4 本地代码页与 UTF-8 冲突确认源文件格式历史包在解压后做 GBK 到 UTF-8 的二次改名5.3 密码强度的防御侧提醒加密 rar 的解密可以完全离线进行密码熵值直接决定安全性。只要密码在 8 位以下且是纯数字GPU 加速的暴力破解工具能在很短时间内跑完字典反过来混合大小写与符号的 12 位以上密码会让离线攻击的成本高到不划算。产品侧如果允许用户自定义解压密码前端应强制复杂度校验服务端在上传 rar 附件时再做一次密码强度检查把弱密码文件挡在网络层。发布前用unrar t -p测试密码把同一文件连测几遍确认密码错误、文件损坏、分卷缺失三种状态都能给出明确提示加密 rar 的兼容性坑就收敛了大半。本文还有配套的精品资源点击获取
返回列表