iloader 如何补齐 iOS 侧载能力缺口:对照 Sideloadly 的源码级差距审计
【免费下载链接】iloaderUser friendly sideloader项目地址: https://gitcode.com/GitHub_Trending/iloa/iloader
iloader 是跨平台 Tauri 侧载工具。本差距审计以 Sideloadly 为标杆,逐条定位 iloader 源码中每项能力的实现边界,帮助贡献者判断补齐某条能力需要改动哪个模块。
口径:数据来源、估算边界与可追溯性
iloader 的核心签名与安装逻辑不在本仓库,而是由外部 crateisideloadv0.5.2 承载(src-tauri/Cargo.toml L26)。本仓库负责 UI 编排、设备通信(idevicecrate)、配对文件管理与错误呈现。因此,本审计的"能力边界"严格限定在iloader 仓库可控范围;isideload内部的签名策略、证书轮换等行为标注为"未测量"。
Sideloadly 是闭源商业软件,其能力描述来自公开文档与社区共识,非黑盒对照测试。文中工作量估算以人时为单位,精度约 ±50%,均标注为"估算"。仓库无 revision history 或变更时间线,结论的可追溯性依赖源码中显式的TODO注释与Cargo.toml锁定的 crate 版本。
能力全景表:13 项能力的实现状态与证据位置
| 能力 | 状态 | 证据位置 | Sideloadly 对照 |
|---|---|---|---|
| IPA 导入安装 | 已实现 | src-tauri/src/sideload.rs | 拖放式;iloader 用文件选择器 |
| Apple ID 登录(含 2FA) | 已实现 | src-tauri/src/account.rs | 一致 |
| 团队账号(>3 应用) | 未实现 | account.rs L253// TODO: Team Selection | 支持,上限 100 应用 |
| 证书查看 / 吊销 | 已实现 | account.rsget_certificates | 一致 |
| App ID 查看 / 删除 | 已实现 | account.rslist_app_ids | 一致 |
| 配对文件生成 + 投递 | 已实现(iloader 独有) | src-tauri/src/pairing.rs | 无此功能 |
| SideStore 一键安装 | 已实现(iloader 独有) | sideload.rsinstall_sidestore_operation | 无此功能 |
| 跨平台(macOS / Win / Linux) | 已实现 | src-tauri/tauri.conf.json | 仅 macOS |
| 自动刷新 / 定期重签 | 未实现 | 仓库内无对应代码 | 支持周级刷新 |
| 拖放安装 | 部分实现 | src/App.tsx L378openFileDialog | 原生拖放 |
| 多设备并发操作 | 未实现 | src-tauri/src/lib.rs L101Mutex<Option<...>> | 未测量 |
| 安全存储(凭证 / 配对缓存) | 已实现 | src-tauri/src/secure_storage.rs | Keychain 单一后端 |
| 国际化(28 语言) | 已实现 | src/locales/ | 英文为主 |
怎么读这张表:iloader 在"配对文件投递"和"跨平台"两条线上是 Sideloadly 的超集;"团队账号"与"自动刷新"是纯工作量空白,不存在许可或 API 壁垒。Sideloadly 侧的"多设备并发"未做基准测试,此处标注为"未测量"而非"不行"——仓库内确实没有并发代码,但也缺少任何性能数据来证明它是瓶颈。
安全存储回退:Keyring 往返测试到 FsStorage 明文降级
安全存储的可用性判定依赖运行期往返测试而非编译期检查,回退到明文存储时会显式打 warn 日志标注不安全。全文仅 55 行,却承载了凭证与配对文件两个敏感数据的持久化(src-tauri/src/secure_storage.rs)。
fn check_keyring_available() -> bool { let entry = keyring::Entry::new("iloader", "test"); if let Ok(entry) = entry { return entry.set_password("test").is_ok() && entry.get_password().is_ok(); } false }这段代码把"keyring 可用"的判定从库依赖变成了运行期行为测试。macOS Keychain 未解锁、Linux Secret Service 未启动等场景都会导致set_password或get_password失败,从而正确触发回退到FsStorage(明文文件存储)。
行为边界:create_sideloading_storage()在回退时打出一条 warn(L46),消息含 "This is insecure"。用户可在 Settings 页面通过force_disable_keyring命令强制走 FsStorage;反向操作会重新检测 keyring,若仍不可用则打 warn 但不改变行为。src-tauri/src/pairing.rs L294-L315 的with_pairing_storage()在每次调用时比对 keyring 状态,若发生运行时切换,会重建存储后端并打 info 日志。
验证方式:在 Settings 勾选"不使用 keyring",日志面板(Ctrl+L)搜索forcefully disabled。出现该 warn 说明回退已生效,凭证将以明文写入~/.local/share/me.nabdev.iloader/下。
设备选择到配对生成:CancellationToken 与 iOS 17.4 版本分叉
设备选择触发一条从枚举到配对生成的串行链,任何一步失败都会终止后续步骤,且用户可随时取消而不阻塞调用线程。入口在 src/Device.tsx 的selectDevice(),调用invoke("set_selected_device")。后端实现在 src-tauri/src/device.rs L124-L163:
let token = tokio_util::sync::CancellationToken::new(); { let mut guard = cancel_state.lock().unwrap(); if let Some(old) = guard.replace(token.clone()) { old.cancel(); } } let pairing_result = pairing_file(&app, device.as_ref().unwrap(), &mut usbmuxd, token.clone()).await;CancellationToken的意义在于:用户可以在配对过程中点击"取消",前一个未完成的配对被立即终止。cancel_pairing命令(device.rs L166-L172)仅对 token 调用cancel(),不阻塞调用线程。每次选择新设备时,旧 token 被replace并立即cancel(),保证不会有两个配对流程并行运行。
配对生成在 src-tauri/src/pairing.rs 的pairing_file()中分两步。第一步generate_lockdown_plist()从 usbmuxd 读取配对记录、开启 lockdown 会话并设置EnableWifiDebugging。第二步根据 iOS 版本分叉(L333):17.4 以下只返回 lockdown plist;17.4+ 追加 rppairing,且有本地缓存(key 为rppairing1.1_file_{udid}),缓存命中时跳过网络握手。最终两个 plist 通过plist!(dict { :< lockdown, :< rppairing })合并为单一 XML 字节流。
失败路径:lockdown 连接失败产生DeviceComsWithMessage;rppairing 生成失败产生RemotePairing。前端 Device.tsx L82 对Canceled类型错误静默处理(不弹 toast),其余错误走 src/ErrorContext.tsx 的err()方法弹出建议面板。
配对投递链:14 应用清单如何映射到 HouseArrest 写入
配对文件投递是 iloader 区别于所有同类工具的核心能力,目标应用清单硬编码在 src-tauri/src/pairing.rs L38-L58 的PAIRING_APPS常量中,共 14 个条目:
const PAIRING_APPS: &[(&str, &str)] = &[ ("SideStore", "ALTPairingFile.mobiledevicepairing;PairingFile_RemoteRP.plist;PairingFile_Lockdown.plist"), ("LiveContainer", "SideStore/Documents/ALTPairingFile.mobiledevicepairing"), ("Feather", "pairingFile.plist"), // ... 共 14 项,含 StikDebug、Protokolle、Antrag 等 ];SideStore 的路径用分号分隔了三个文件名,place_file()(L165-L186)会逐一切分并逐个通过 AFC 协议写入。这意味着 SideStore 的配对文件实际上是三个独立 plist 的合并体,而非单一文件。新增受支持应用只需往常量加一行,投递逻辑无需改动。
写入路径:place_file()先通过 HouseArrest 的vend_documents(bundle_id)打开目标应用的沙箱 Documents 目录,再对每个文件执行mk_dir → open(Wr) → write_entire → close。若目标应用未安装,installed_pairing_apps()返回空列表,前端显示"未找到受支持的应用"。iOS 17.4 以下设备的配对文件只含 lockdown 部分,体积更小。
验证方式:安装 SideStore 后打开 Pairing 页面,点击"Place"。若提示 "not found",说明get_sidestore_info()未匹配到 bundle ID(src-tauri/src/sideload.rs L176-L179),需确认设备上已安装 SideStore。
机制串联:一次 SideStore 安装的六步调用链
一次 SideStore 安装跨越六个阶段,任何一步的失败都会被Operation结构体捕获并向前端发射带错误类型的失败事件。
- 前端触发:src/App.tsx 的
startOperation()调用invoke("install_sidestore_operation"),同时注册operation_install_sidestore事件监听。 - 下载:src-tauri/src/sideload.rs L106-L138 从 GitHub Releases 下载 IPA 到临时目录,
op.start("download")发射开始事件。 - 安装:
op.move_on("download", "install")后,复用sideload()函数,通过SideloaderGuard::take()从全局Mutex<Option<Sideloader>>取出实例执行install_app()。 - 查询:
op.move_on("install", "pairing")后,get_sidestore_info()通过 InstallationProxy 查询设备已安装应用列表,匹配 "SideStore" 显示名。 - 投递:
place_file()打开 HouseArrest → vend_documents → AFC 写入三个配对文件。 - 状态回报:每步通过 src-tauri/src/operation.rs 的
Operation::start/complete/fail向事件通道发射OperationUpdate,前端 reducer 按updateType更新步骤 UI。
失败分支:第 4 步若 SideStore 未安装,get_sidestore_info返回None,操作在pairing阶段失败,错误类型为HouseArrest,消息为 "The device did not report SideStore's bundle ID as installed"(sideload.rs L176-L179)。第 2 步下载失败则错误类型为Download,包含 HTTP 状态码。
亲手验证:五条命令对照日志关键字
以下命令在 Linux 上验证(前置:bun + Rust + usbmuxd 已安装):
- 确认 usbmuxd 可达:
busctl --user list | grep usbmuxd。输出为空说明 usbmuxd 未运行,iloader 启动后list_devices返回Usbmuxd类型错误。 - 从源码构建:
bun i && bun tauri dev。构建成功说明isideloadv0.5.2 与idevicev0.1.68 均正确解析。 - 验证 keyring 回退:Settings 勾选"不使用 keyring",日志面板(Ctrl+L)搜索
forcefully disabled。出现该 warn 说明回退生效,凭证以明文写入~/.local/share/me.nabdev.iloader/。 - 验证配对缓存:选择设备后搜索
Generating new RPPairing。首次选择设备应出现此 info 日志;再次选择同一设备不应出现(命中缓存)。点击"删除已存储的 RPPairing"后再选设备,日志应重新出现。 - 验证 SideStore 安装步骤:点击"Install SideStore",观察 OperationView 三步进度(download → install → pairing)。pairing 步骤失败且提示 "not found" 说明设备未装 SideStore,需先手动安装。
三类空白与推进路径
iloader 相对 Sideloadly 的空白归为三类。纯工作量(无 API 或许可壁垒):团队账号(account.rs L253 的 TODO,需 isideload 侧配合,估算 20-40 人时)、自动刷新(仓库内无对应代码,估算 30-50 人时)、拖放交互(用 TaurionDragDrop替代文件选择器,约 5 人时)。未测量:多设备并发(Mutex全局锁是否存在性能瓶颈,无基准数据,不能直接判定为"不行")。所有者决策:无——当前空白均不涉及许可或专有 API 限制。推进建议:先补拖放(ROI 最高),再推团队账号(用户感知最强),最后做自动刷新(需与 isideload 的签名策略对齐)。
【免费下载链接】iloaderUser friendly sideloader项目地址: https://gitcode.com/GitHub_Trending/iloa/iloader
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考