系统要求
Headless API 让您无需任何应用界面,即可通过 ADB 或任意自动化工具完全控制 HideMyAndroid。此为 高级版 专属功能。
- 高级账户 — Headless API 仅限高级版使用。
- 应用版本 1.2.8 或更高。 此后新增的内容都是额外字段或方法,因此 1.2.8 仍可正常使用 — 但较新的部分需要较新的版本:
hook_spoof_uptime需要 1.3.4+,geo与profile.duplicate需要 1.4.5+,而整个备份/恢复方法组需要 1.5.3+。旧版本会忽略它无法识别的字段,并且依然返回ok=true— 但无法识别的方法动静更大:在 1.5.3 之前的版本上调用备份/恢复方法组会返回BAD_REQUEST,且error_message为 “Unknown method: …”。如果某项设置似乎毫无作用,请通过 status 查看当前运行的version— 正式打包的发行版会如实上报版本号,而在版本号提升之前自行编译的构建可能已包含某项功能,却仍报告旧版本号。 - Root + LSPosed — 与 HideMyAndroid 所需的配置相同。请参阅 安装指南。
- ADB 已连接至设备(
adb devices可列出已连接设备)。 - 设备已联网 — 仅在启用代理时需要(会进行实时检测)。
⚠️ 只有使用代理的配置文件才需要 VPN 权限。无界面模式无法弹出系统的 VPN 授权对话框,因此请先在应用的 Headless API 界面授权一次。若未授权,激活带代理的配置文件仍会激活该配置文件,但代理不会连接,调用会返回
INTERNAL并说明此情况。
身份认证
在应用中打开 设置 → 开发者 → Headless API,然后开启 启用。系统会自动生成一个密钥 — 点击 复制。每个请求都需要将此密钥作为 token 参数传入。
请妥善保管密钥 — 任何拥有该密钥且能访问 ADB 的人都可以控制您的配置文件。重新生成 将生成新密钥(旧密钥立即失效);退出登录将清除密钥。
在本文档中,请将 <your_access_token> 替换为您的密钥,将 <profile_id> 替换为 profile.create 返回的 id。
发起请求
共有两种传输方式,根据值中是否包含冒号 : 来选择
| 传输方式 | 适用场景 | 命令 |
|---|---|---|
content call | 读取操作,以及不含 : 的值(name、gmails、包名) | adb shell content call |
am broadcast | JSON 对象(hookFlags、proxy、deviceMock、sim)— 这些值包含 : | adb shell am broadcast |
content call 会在冒号处分割每个 --extra 参数,因此无法传递 JSON — 这也是 JSON 值需要通过广播发送的原因。
只有三个方法提供 broadcast 形式:HEADLESS_UPDATE(profile.update)、HEADLESS_SET_ACTIVE 和 HEADLESS_DEACTIVATE。其余十五个 — status、所有读取操作、profile.create、profile.duplicate、profile.delete、目标应用相关调用以及整个备份/恢复方法组 — 仅支持 content call。不存在 HEADLESS_CREATE,也不存在 HEADLESS_BACKUP,无需去找。
broadcast 并非只能传 JSON。HEADLESS_UPDATE 恰好转发七个 extra 参数 — name、hookFlags、proxy、geo、deviceMock、sim、gmails — 因此 name 与 gmails 通过两种传输方式都可以发送。上方表格说明的是哪种方式更方便,而非哪种方式可行。凡是不在这七个之列的 extra 参数,都会被直接丢弃且不报错。
响应说明。 成功时返回 ok=true(content call)或 result=0(广播);失败时会附加 error_code 和 error_message。请参阅 错误代码。每个方法都需要传入 token。点击下方任意操作可展开其参数、请求与响应详情。
状态
READ status 检查 API 是否就绪 content call
Parameters
No parameters.
Request
adb shell content call --uri content://com.wowsoftware.hidemyandroid.headless --method status --extra token:s:<your_access_token> Response ok=true
Bundle[{data={"premium":true,"featureEnabled":true,"freshnessOk":true,"activeProfileId":"a1b2c3d4-...","version":"1.5.3"}, ok=true}] 字段说明:premium(高级版状态)、featureEnabled(功能是否启用)、freshnessOk、activeProfileId(当前激活的配置文件 id,无则为 null)、version(版本号)。当应用在过去 24 小时内完成过一次在线许可证验证时,freshnessOk 为 true。该检查本身是离线的 — headless 请求从不联网,只读取已保存的结果,premium 同样是离线读取。请每天至少打开一次应用,以保持 freshnessOk 为 true。
💡
status是许可证过期或过时后唯一仍会响应的方法 — 其余所有调用都只会返回LICENSE_EXPIRED或LICENSE_STALE。因此当请求被拒绝时,正是通过它来区分这两种情况:查看premium判断高级版是否真的到期,查看freshnessOk判断是否只需打开一次应用即可。status仍然受FEATURE_DISABLED与UNAUTHORIZED限制,因此功能未启用或令牌错误在这里的表现与别处一致。
配置文件
READ profile.list 列出所有配置文件 content call
Parameters
No parameters.
Request
adb shell content call --uri content://com.wowsoftware.hidemyandroid.headless --method profile.list --extra token:s:<your_access_token> Response ok=true
Bundle[{data=[{"id":"a1b2...","name":"Demo","isActive":true,"createdAt":1717000000000,"updatedAt":1717000500000}], ok=true}] READ profile.get 获取单个配置文件的完整信息 content call
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
id | string | required | 配置文件的 id。 |
Request
adb shell content call --uri content://com.wowsoftware.hidemyandroid.headless --method profile.get --extra token:s:<your_access_token> --extra id:s:<profile_id> Response ok=true
Bundle[{data={"id":"a1b2...","name":"Demo","isActive":false,"hookFlags":{"hook_wifi":true,...},"proxy":{"enabled":false,...},"geo":{"source":"PROXY",...},"deviceMock":{"enabled":false,...},"sim":{"enabled":false,"simCards":[]},"gmails":[],"targetApps":["com.whatsapp"]}, ok=true}] CREATE profile.create 创建配置文件(返回其 id) content call
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
name | string | required | 配置文件的标签名称。 |
Request
adb shell content call --uri content://com.wowsoftware.hidemyandroid.headless --method profile.create --extra token:s:<your_access_token> --extra name:s:Demo Response ok=true
Bundle[{data={"id":"a1b2c3d4-..."}, ok=true}] 请将此 id 作为 <profile_id> 用于后续调用。
CREATE profile.duplicate 克隆配置文件并生成全新身份 content call
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
id | string | required | 要复制的源配置文件 id。 |
Request
adb shell content call --uri content://com.wowsoftware.hidemyandroid.headless --method profile.duplicate --extra token:s:<your_access_token> --extra id:s:<profile_id> Response ok=true
Bundle[{data={"id":"e5f6a7b8-...","name":"Brave Falcon 42"}, ok=true}] 新的 id 与自动生成的名称会一并返回 — profile.create 只返回 id,因此请勿认为两者的返回内容相同。
⚠️ 名称由应用自动生成,无法在本次调用中指定。若需要自定义名称,请紧接着使用 profile.update 重命名副本。
副本会保留哪些内容
以与应用内「复制」菜单相同的方式克隆配置文件 — 需要应用 1.4.5+。各项设置会被保留,但每一个身份标识值都会重新生成,因此副本拥有自己的指纹,而不是原配置文件的孪生体。本方法没有 broadcast 形式:发送后不管的广播无法把新 id 交还给您,而这正是该调用的意义所在。
| 项目 | 在副本中 |
|---|---|
目标应用、hookFlags、proxy(含已通过检测的地理信息)、geo、隐藏的软件包 | 原样保留 |
| 设备的每一项标识 — 既包括配置文件层面的,也包括配置文件中每个应用各自的 | 重新签发,因此副本拥有自己的指纹,而不是原配置文件的孪生体 |
deviceMock(启用时) | 切换为另一套设备模板 |
sim | 国家不变,号码更新 |
| 备份软件包 | 不会复制 — 备份以 {package}-{profileId} 为键,因此副本不拥有任何备份,从空白开始 |
| 虚拟 Gmail 账号 | 若源配置文件启用了 hook_virtual_accounts,则分配一个全新地址;未启用则为空列表 |
| 名称 | 自动生成且保证不重复,形如 Brave Falcon 42 — 您无法指定,因此它才会被返回给您 |
| 激活状态 | 始终为 isActive: false — 复制操作绝不会激活配置文件 |
若想使用自定义名称,请先复制,再通过第二次调用重命名:
# 1. duplicate — the new id and its generated name come back together
adb shell content call --uri content://com.wowsoftware.hidemyandroid.headless --method profile.duplicate --extra token:s:<your_access_token> --extra id:s:<source_profile_id>
# 2. rename the copy — profile.duplicate never takes a name of your own
adb shell content call --uri content://com.wowsoftware.hidemyandroid.headless --method profile.update --extra token:s:<your_access_token> --extra id:s:<new_profile_id> --extra name:s:"My Profile" UPDATE profile.update 修改配置文件的设置 content call / broadcast
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
id | string | required | 配置文件的 id。 |
name | string | optional | 新的配置文件标签名称(content call)。 |
gmails | string[] | optional | 虚拟 @gmail.com 账号(content call)。 |
hookFlags | object | optional | 伪装功能的开/关开关(broadcast)。 |
proxy | object | optional | 代理配置(broadcast)。 |
geo | object | optional | 位置来源 — 代理或自定义(broadcast)。需要应用 1.4.5+。 |
deviceMock | object | optional | 设备型号伪装(broadcast)。 |
sim | object | optional | SIM 卡/运营商伪装(broadcast)。 |
Request
content call — 普通值
adb shell content call --uri content://com.wowsoftware.hidemyandroid.headless --method profile.update --extra token:s:<your_access_token> --extra id:s:<profile_id> --extra name:s:"My Profile" broadcast — JSON 配置
adb shell am broadcast -a com.wowsoftware.hidemyandroid.HEADLESS_UPDATE -p com.wowsoftware.hidemyandroid -e token <your_access_token> -e id <profile_id> -e hookFlags '{"hook_wifi":false,"hook_nearby_bluetooth":false}' Response ok=true
两种方式均返回完整的已更新配置文件。每个 JSON 字段的说明请参阅"配置"章节。
⚠️ hookFlags 会替换整个标志集 — 未填写的标志将恢复为各自的默认值:除 hook_spoof_uptime 默认为关闭外,其余标志默认均为开启。也就是说,一次未包含 hook_spoof_uptime 的更新会悄悄将其关闭。若只想修改部分标志并保留其余设置,请先执行 profile.get 获取完整映射,编辑后再整体发送。
DELETE profile.delete 永久删除配置文件 content call
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
id | string | required | 配置文件的 id。 |
Request
adb shell content call --uri content://com.wowsoftware.hidemyandroid.headless --method profile.delete --extra token:s:<your_access_token> --extra id:s:<profile_id> Response ok=true
Bundle[{data={}, ok=true}] ⚠️ 删除配置文件也会一并删除它位于 /sdcard/HideMyAndroid_Backups/ 下的应用数据备份 — 如仍需保留,请先将其复制到设备之外。此外自 1.5.3 起,当备份/恢复任务仍占用着执行槽位时,profile.delete 会返回 BUSY — 即便是已取消的任务也一样;请持续重试,直到不再返回 BUSY。
激活
配置文件只有在激活状态下才会执行伪装,并且同一时间只会有一个配置文件处于激活状态。profile.setActive 会直接切换当前激活的配置文件 — 之前处于激活状态的那个会被自动停用,因此无需事先调用 profile.deactivate。
⚠️ 激活会清除目标应用的数据。
profile.setActive不只是重启它们:它会强制停止每个目标应用并清除其数据,使其以全新状态启动,从而真正应用新的身份。这是有意为之 — 但这也意味着这些应用内的一切都会消失,包括已登录的会话,在应用内,同样的操作会先请求确认并提示您使用备份功能;而无界面调用不会弹出任何对话框,命令会直接执行 — 因此本提示就是您能得到的唯一警告。在无界面模式下,切换前的安全网是先调用backup.start(1.5.3+)。另外自 1.5.3 起,当备份/恢复任务仍占用着执行槽位时,profile.setActive与profile.deactivate会返回BUSY— 即便是已取消的任务也一样;请持续重试,直到不再返回BUSY。
ACTION profile.setActive 激活配置文件 — 开始伪装 content call / broadcast
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
id | string | required | 配置文件的 id。通过 broadcast 传入时,id 与 profile_id 两种写法均可。 |
Request
content call — 推荐
adb shell content call --uri content://com.wowsoftware.hidemyandroid.headless --method profile.setActive --extra token:s:<your_access_token> --extra id:s:<profile_id> broadcast — 用于自动化
adb shell am broadcast -a com.wowsoftware.hidemyandroid.HEADLESS_SET_ACTIVE -p com.wowsoftware.hidemyandroid -e token <your_access_token> -e id <profile_id> Response ok=true
Bundle[{data={"id":"a1b2...","isActive":true}, ok=true}] ACTION profile.deactivate 停用当前激活的配置文件 — 停止伪装 content call / broadcast
Parameters
No parameters.
Request
content call — 推荐
adb shell content call --uri content://com.wowsoftware.hidemyandroid.headless --method profile.deactivate --extra token:s:<your_access_token> broadcast — 用于自动化
adb shell am broadcast -a com.wowsoftware.hidemyandroid.HEADLESS_DEACTIVATE -p com.wowsoftware.hidemyandroid -e token <your_access_token> Response ok=true
Bundle[{data={}, ok=true}] 无需传入 id — 此操作会停用当前处于激活状态的配置文件。
content call 是推荐使用的方式:它是同步的,并会打印返回的 Bundle。HEADLESS_SET_ACTIVE 和 HEADLESS_DEACTIVATE 广播可在 Tasker 等自动化工具中完成同样的工作。它们以 ordered broadcast 方式响应,始终会回传数据:成功时 am broadcast 打印 result=0,并在 data="…" 中带回结果 JSON;失败时打印 result=1 与 data="{"error_code":…,"error_message":…}"。因此它们并非严格意义上的「发送后不管」 — 只要解析 data=,就能得到与 content call 相同的返回结果。HEADLESS_SET_ACTIVE 接受 -e id 或 -e profile_id 两种形式传入配置文件 id;HEADLESS_DEACTIVATE 则完全不需要 id。与往常一样,请务必加上 -p com.wowsoftware.hidemyandroid。
目标应用
目标应用是配置文件将要伪装的应用程序。
READ profile.getApps 列出配置文件的目标应用 content call
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
id | string | required | 配置文件的 id。 |
Request
adb shell content call --uri content://com.wowsoftware.hidemyandroid.headless --method profile.getApps --extra token:s:<your_access_token> --extra id:s:<profile_id> Response ok=true
Bundle[{data=[{"packageName":"com.whatsapp"}], ok=true}] CREATE profile.addApp 向配置文件添加目标应用 content call
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
id | string | required | 配置文件的 id。 |
packageName | string | required | 应用的包名。 |
Request
adb shell content call --uri content://com.wowsoftware.hidemyandroid.headless --method profile.addApp --extra token:s:<your_access_token> --extra id:s:<profile_id> --extra packageName:s:com.whatsapp Response ok=true · updated app list
Bundle[{data=[{"packageName":"com.whatsapp"}], ok=true}] ⚠️ 重复添加同一包名将返回 BAD_REQUEST。
DELETE profile.removeApp 从配置文件中移除目标应用 content call
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
id | string | required | 配置文件的 id。 |
packageName | string | required | 要移除的应用。 |
Request
adb shell content call --uri content://com.wowsoftware.hidemyandroid.headless --method profile.removeApp --extra token:s:<your_access_token> --extra id:s:<profile_id> --extra packageName:s:com.whatsapp Response ok=true · updated app list
Bundle[{data=[], ok=true}] ⚠️ 移除一个本就不在配置文件中的软件包同样会成功且不改变任何内容 — 这不算错误。此行为与 addApp 刻意不同,后者重复添加会返回 BAD_REQUEST。
备份与恢复
1.5.3 新增。这组方法可将配置文件中的应用数据复制为设备上的归档文件,并在日后恢复回去 — 与应用内 Manage Backups 的功能相同,只是没有界面。全部六个方法都仅支持 content call(没有 broadcast 形式),并且两个 *.start 调用是异步的:它们会立即返回一个 jobId,然后在后台继续工作 — 请轮询 backup.job 跟踪进度。备份单个应用就可能需要数分钟。
⚠️ 同一时间只能运行一个任务。在任务运行期间再次调用
*.start会返回BUSY,并在error_message中给出正在运行的jobId。此外,两个*.start调用要求目标配置文件处于激活状态 — 否则返回REQUIRES_ACTIVE_PROFILE,且没有任何绕过开关。其余四个方法对任意配置文件均可使用。并且与 Headless API 的其他地方一样,任何调用都不会请求确认 — 命令会直接执行。
ACTION backup.start 为当前激活的配置文件启动备份任务 content call
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
id | string | required | 配置文件的 id — 必须是当前激活的配置文件。 |
packages | string | optional | 要备份的包名,以逗号分隔(不含空格)。省略时将备份该配置文件的所有目标应用。每个包名都必须属于该配置文件。 |
Request
content call — 所有目标应用
adb shell content call --uri content://com.wowsoftware.hidemyandroid.headless --method backup.start --extra token:s:<your_access_token> --extra id:s:<profile_id> content call — 仅指定的软件包
adb shell content call --uri content://com.wowsoftware.hidemyandroid.headless --method backup.start --extra token:s:<your_access_token> --extra id:s:<profile_id> --extra packages:s:com.twitter.android,com.facebook.katana Response ok=true · job accepted
Bundle[{data={"jobId":"f0e1d2c3-...","type":"backup","total":2,"packages":["com.twitter.android","com.facebook.katana"],"foregroundHeld":true}, ok=true}] 调用在任务被接受的那一刻即返回 — 不会等待复制完成。total 表示任务将处理的应用数量;请轮询 backup.job 跟踪进度。关于 foregroundHeld 能保证(以及不能保证)什么,请参阅下方说明。
⚠️ 备份绝不会强制停止或清除应用。为了读取一致的快照,它会在归档每个组件时短暂暂停应用(SIGSTOP),随后再恢复运行(SIGCONT)— 应用保持运行,不会丢失任何内容。对已有备份的软件包再次备份会替换旧的归档:每个应用在每个配置文件下只有一个备份,没有历史记录。
ACTION restore.start 将已备份的应用数据恢复到当前激活的配置文件 content call
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
id | string | required | 配置文件的 id — 必须是当前激活的配置文件。备份只能恢复到创建它的那个配置文件。 |
packages | string | optional | 要恢复的包名,以逗号分隔(不含空格)。省略时将恢复该配置文件中所有拥有备份的应用 — 没有备份的应用会被静默跳过。显式指定包名时则是快速失败:只要有一个软件包缺少备份,整个调用就会以 NO_BACKUP 失败,任何内容都不会被恢复。 |
Request
adb shell content call --uri content://com.wowsoftware.hidemyandroid.headless --method restore.start --extra token:s:<your_access_token> --extra id:s:<profile_id> Response ok=true · job accepted
Bundle[{data={"jobId":"09a8b7c6-...","type":"restore","total":1,"packages":["com.twitter.android"],"foregroundHeld":true}, ok=true}] 任务模型与 backup.start 相同 — 响应立即返回,type 字段为 "restore"。请轮询 backup.job 跟踪进度;不存在单独的 restore.job。
⚠️ 恢复会强制停止目标应用(am force-stop)且不会重新启动它,随后将归档解压到 /data/data/<pkg> 之上,而不会先清空目录 — 因此应用在备份之后创建的文件会保留下来。此外,备份以软件包 + 配置文件为键,这正是不存在跨配置文件恢复的原因 — 您无法把一个配置文件的备份灌入另一个配置文件。
READ backup.job 轮询任务的进度与结果 content call
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
jobId | string | optional | 要查看的任务。省略时读取最近一次任务。 |
Request
content call — 指定任务
adb shell content call --uri content://com.wowsoftware.hidemyandroid.headless --method backup.job --extra token:s:<your_access_token> --extra jobId:s:<job_id> content call — 最近一次任务(不传 jobId)
adb shell content call --uri content://com.wowsoftware.hidemyandroid.headless --method backup.job --extra token:s:<your_access_token> Response ok=true
# while it runs
Bundle[{data={"jobId":"f0e1d2c3-...","type":"backup","profileId":"a1b2...","state":"RUNNING","total":2,"done":0,"ok":0,"failed":0,"currentPackage":"com.twitter.android","currentComponent":"Internal Data","progress":0.31,"results":[],"error":null,"foregroundHeld":true,"startedAt":1712345678901,"finishedAt":null}, ok=true}]
# when it finishes — note: DONE even though one app failed
Bundle[{data={"jobId":"f0e1d2c3-...","type":"backup","profileId":"a1b2...","state":"DONE","total":2,"done":2,"ok":1,"failed":1,"currentPackage":null,"currentComponent":null,"progress":1.0,"results":[{"packageName":"com.twitter.android","ok":true,"error":null},{"packageName":"com.facebook.katana","ok":false,"error":"tar exited 2"}],"error":null,"foregroundHeld":true,"startedAt":1712345678901,"finishedAt":1712345699999}, ok=true}] 两种任务类型共用这一个方法 — type 字段为 "backup" 或 "restore"。state 为 RUNNING、DONE、FAILED 或 CANCELLED;progress 在整个任务范围内从 0 到 1;startedAt / finishedAt 为 epoch 毫秒时间戳,任务运行期间 finishedAt 保持为 null。DONE 只表示任务执行到了最后 — 不代表每个应用都成功 — 因此请务必读取 failed 和 results[](每个应用一条 {packageName, ok, error})。currentComponent 是人类可读的阶段名称("Internal Data"、"Device Encrypted Data"、"External Data"、"Media"、"OBB"、"Permissions"、"SSAID")— 刻意与 backup.list 中 components[] 的字符串不同。对任意配置文件均可调用。只会保留最近的五个任务 — 未知或更早的 jobId 会返回 NOT_FOUND,在从未运行过任何任务时轮询同样如此。
ACTION backup.cancel 取消正在运行的任务 content call
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
jobId | string | optional | 要取消的任务。省略时取消最近一次任务。 |
Request
adb shell content call --uri content://com.wowsoftware.hidemyandroid.headless --method backup.cancel --extra token:s:<your_access_token> --extra jobId:s:<job_id> Response ok=true · job snapshot
返回取消后的任务快照 — 与 backup.job 返回的结构相同。
⚠️ 在处理某个应用的中途取消,会让该应用的归档处于半写入状态:该应用不会被加入备份列表,残留文件的状态是未定义的。请勿从中恢复 — 请对该软件包执行 backup.delete 后重新备份。此外,任务快照会立即变为 CANCELLED(并设置 finishedAt),但底层的 root tar 无法在文件中途被打断,会继续运行 — 因此在已经显示 CANCELLED 之后,任务仍可能占用着执行槽位(请参阅下方说明)。
READ backup.list 列出配置文件已保存的备份 content call
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
id | string | required | 配置文件的 id — 任意配置文件均可,不限于当前激活的那个。 |
Request
adb shell content call --uri content://com.wowsoftware.hidemyandroid.headless --method backup.list --extra token:s:<your_access_token> --extra id:s:<profile_id> Response ok=true
Bundle[{data=[{"packageName":"com.twitter.android","appName":"X","timestamp":1712345678901,"totalSize":12345678,"components":["INTERNAL_DATA","EXTERNAL_DATA","OBB"]}], ok=true}] 每个已备份的应用对应一个条目。appName 是备份时记录的显示名称(读取自归档中的 metadata.json,而非从软件包推导)。timestamp 为 epoch 毫秒时间戳,totalSize 单位为字节,components[] 使用枚举名称:INTERNAL_DATA、DEVICE_ENCRYPTED、EXTERNAL_DATA、MEDIA、OBB、PERMISSIONS、SSAID。
DELETE backup.delete 从配置文件中删除某个应用的备份 content call
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
id | string | required | 配置文件的 id。 |
packageName | string | required | 要删除其备份的应用。 |
Request
adb shell content call --uri content://com.wowsoftware.hidemyandroid.headless --method backup.delete --extra token:s:<your_access_token> --extra id:s:<profile_id> --extra packageName:s:com.twitter.android Response ok=true
Bundle[{data={}, ok=true}] 同步操作 — 不会创建任务;备份文件夹会被当场删除。删除一个不存在的备份不算错误:该调用是幂等的,依然返回 ok=true 与 data={}。NOT_FOUND 仅表示配置文件 id 不存在;packageName 格式错误则返回 BAD_REQUEST。
任务的运行机制
DONE并不代表每个应用都成功。它只表示任务执行到了最后。即便某个应用失败,任务仍可能以DONE结束 — 请务必读取failed和results[]。- 激活现在会等待任务。当任务占用着执行槽位时,
profile.setActive、profile.deactivate和profile.delete都会返回BUSY— 即便是您已经取消的任务也一样,因为底层的 roottar无法在文件中途被停止,而且快照中没有任何字段会报告槽位状态。以DONE或FAILED自然结束的任务几乎会立即释放槽位;取消之后,请勿把CANCELLED当作「槽位已空」— 只需重试该调用,直到不再返回BUSY。 foregroundHeld是一项观测值,而非承诺。它报告的是是否有前台服务在保护任务不被系统杀死。在 API 36 上实测为true,但即便是true也只说明服务启动请求被接受了 — 后续将其提升为前台的步骤在某些设备上仍可能静默失败。对于耗时较长的任务,请保持设备唤醒,而不要依赖此字段。- 备份的存储位置。
/sdcard/HideMyAndroid_Backups/<packageName>-<profileId>/— 每个应用在每个配置文件下各有一个文件夹,其中存放.tar.gz归档(data.tar.gz、data_ext.tar.gz、media.tar.gz等)以及metadata.json,均由 roottar写入。正是{package}-{profileId}这一键值使得恢复只能在同一配置文件内进行。通过无界面方式创建的备份同样会出现在应用的 Manage Backups 界面中。
配置
以下是通过 profile.update 发送的配置值。创建配置文件时的默认值:
| 设置项 | 默认值 | 启用方式… |
|---|---|---|
| hookFlags (all 21) | ✅ ON — 但 hook_spoof_uptime 为 ❌ OFF | 默认已开启。仅对需要关闭的标志发送 false — 并对 hook_spoof_uptime 发送 true,它是唯一默认关闭的标志。 |
| proxy | ❌ OFF | 添加 "enabled":true |
| geo | PROXY | 发送 "source":"CUSTOM" 并附上坐标、countryCode 和 timezone,即可在没有代理的情况下设置位置 |
| deviceMock | ❌ OFF | 添加 "enabled":true |
| sim | ❌ OFF | 添加 "enabled":true |
| gmails | empty | 发送邮件地址(虚拟账号默认开启) |
⚠️ 包含
enabled:false的配置将被 保存但不生效 — 值会被保存以便日后启用,但在enabled:true之前不会执行任何伪装。geo是个例外:它没有enabled开关。只要geo能解析出可用的位置,hook_geo_*标志就会生效 — 来源可以是source: CUSTOM,也可以是已设置enabled:true且通过实时检测的代理。
hookFlags
默认:除 hook_spoof_uptime 为关闭外,其余标志全部开启。 格式为 "flag": true|false 的映射表。一次更新会 替换整个映射表,但仅限于您实际发送的那份映射表:完全不带 hookFlags 参数的更新不会改动任何标志。在您发送的映射表内,每个未填写的标志都会恢复为各自的默认值,因此其余 20 个会恢复为开启,而 hook_spoof_uptime 即便您之前已将其开启,也会恢复为关闭。若只想修改部分标志并保留其余设置,请先执行 profile.get 获取完整映射,编辑后再整体发送。
| 标志 | 功能说明 |
|---|---|
hook_hide_dev_opts | 隐藏开发者选项 |
hook_hide_vpn | 隐藏 VPN |
hook_hide_airplane_mode | 隐藏飞行模式 |
hook_hide_proxy | 隐藏系统代理设置 |
hook_hide_root | 隐藏 Root |
hook_hide_lsposed | 隐藏 LSPosed |
hook_spoof_installer | 伪装安装来源 |
hook_package_info | 伪装软件包信息/签名 |
hook_lan_scan_block | 阻止局域网扫描 |
hook_identifiers_partly | 伪装基础设备标识 |
hook_identifiers_fully | 伪装完整的设备标识集合 — 包含 hook_identifiers_partly 覆盖的全部内容 |
hook_wifi | 伪装已连接 Wi-Fi 网络的信息 |
hook_nearby_wifi | 伪装附近 Wi-Fi 扫描结果 |
hook_nearby_bluetooth | 伪装附近蓝牙设备 |
hook_realistic_sensor | 使用真实传感器数据 |
hook_sensor_accelerometer | 伪装加速度计(需开启 hook_realistic_sensor) |
hook_spoof_uptime | 伪装设备运行时长 — 让设备看起来已经运行了更长时间。高级版,实验性功能。默认关闭 — 唯一默认关闭的标志。需要应用 1.3.4+。 |
hook_virtual_accounts | 启用虚拟 Google 账号(gmails 需要此项开启) |
hook_geo_gps | 伪装 GPS 位置(需要 geo — 来自代理或自定义) |
hook_geo_locale | 伪装语言/地区(需要 geo — 来自代理或自定义) |
hook_geo_timezone | 伪装时区(需要 geo — 来自代理或自定义) |
proxy
默认:关闭。 启用 enabled:true 后,应用将通过代理建立真实连接,读取其位置信息,并填充 countryCode/lat/lon/timezone。实时检测最长耗时约 8 秒;检测失败的代理将返回 PROXY_INVALID 且不会被保存。这四个字段是 输出字段 — 由应用写入,因此您在其中发送的任何内容都会被覆盖。若要手动设置位置,请改用 geo 的 source: CUSTOM;该方式完全不需要代理。profile.get 会返回包含这四个字段的代理配置,但绝不会回显 username 或 password。
| 字段 | 类型 | 默认值 | 含义 / 约束 |
|---|---|---|---|
host | string | "" | 代理 IP / 主机名 |
port | int | 0 | 端口 — 1–65535,仅在启用代理时才会校验 |
protocol | string | HTTP | HTTP、SOCKS4 或 SOCKS5 |
username | string | "" | 认证用户名(可选)— profile.get 绝不会返回 |
password | string | "" | 认证密码(可选)— profile.get 绝不会返回 |
countryCode | string | "" | 输出字段 — 两位字母国家代码,由实时检测填充 |
lat | double | 0 | 输出字段 — 由实时检测填充 |
lon | double | 0 | 输出字段 — 由实时检测填充 |
timezone | string | "" | 输出字段 — IANA 名称,由实时检测填充 |
adb shell am broadcast -a com.wowsoftware.hidemyandroid.HEADLESS_UPDATE -p com.wowsoftware.hidemyandroid -e token <your_access_token> -e id <profile_id> -e proxy '{"enabled":true,"host":"10.0.0.1","port":1080,"protocol":"SOCKS5"}' geo
默认值:{"source":"PROXY"}。需要应用 1.4.5+。 配置文件的位置信息由此而来,共有两个来源 — 通过 source 选择其一。PROXY 使用代理实时检测时读取到的位置。CUSTOM 允许您自行设置坐标、时区和地区,完全不需要代理 — 因此您可以把配置文件放在东京,而流量走向任意位置,或者根本不走代理。随后三个 hook_geo_* 标志会分别独立控制各个部分:GPS、地区 + 语言、时区。
⚠️ 请注意字段名称的差异:geo 中使用 latitude/longitude,而上方 proxy 中使用简写的 lat/lon。这是两个彼此独立的对象,并非同义别名 — 在 geo 数据中使用简写名称会被直接忽略。
| 字段 | 类型 | 默认值 | 含义 / 约束 |
|---|---|---|---|
source | string | PROXY | 必填。 必须恰好为 PROXY 或 CUSTOM — 缺失或拼写错误会返回 BAD_REQUEST,绝不会被悄悄当作 PROXY 处理 |
latitude | double | 0 | CUSTOM 必填 — 取值须在 -90 到 90 之间;0/0 视为未设置 |
longitude | double | 0 | CUSTOM 必填 — 取值须在 -180 到 180 之间;0/0 视为未设置 |
countryCode | string | "" | CUSTOM 必填 — 两位字母,如 JP。输入不区分大小写,返回时始终为大写 |
timezone | string | "" | CUSTOM 必填 — IANA 名称,如 Asia/Tokyo。仅检查是否为空 — 请参阅下方警告 |
language | string | "" | 可选 — 两位 ISO 639-1 代码,如 ja,而非 ja-JP 这样的完整标签。留空时将根据 countryCode 推导,且始终以小写形式存储。仅 CUSTOM 可显式设置;在 PROXY 路径下始终为自动推导 |
⚠️
source: CUSTOM必须完整提供:一组不为0/0且在有效范围内的坐标、两位字母的countryCode,以及timezone。缺少任意一项都会返回BAD_REQUEST— 它不会回退到代理。应用绝不会进行地理编码,也不会联网替您填充这些字段。若两个来源最终都不可用,则不会加载任何地理位置 Hook,真实位置将会暴露。
🛑
timezone是唯一没有被真正校验的字段。 它只检查是否为空,从不与 IANA 数据库比对。像Asia/Tokyoo这样的拼写错误会被接受、返回ok=true、并由profile.get原样回显,然后在设备上悄悄变成 GMT。整个链路中没有任何地方会报错,因此请精确复制名称。坐标则恰恰相反 — 它们确实会做范围校验,取值错误会立刻以BAD_REQUEST失败。
CUSTOM — 手动设置位置,无需代理
adb shell am broadcast -a com.wowsoftware.hidemyandroid.HEADLESS_UPDATE -p com.wowsoftware.hidemyandroid -e token <your_access_token> -e id <profile_id> -e geo '{"source":"CUSTOM","latitude":35.6812,"longitude":139.7671,"countryCode":"JP","timezone":"Asia/Tokyo","language":"ja"}' PROXY — 使用代理提供的位置(默认)
adb shell am broadcast -a com.wowsoftware.hidemyandroid.HEADLESS_UPDATE -p com.wowsoftware.hidemyandroid -e token <your_access_token> -e id <profile_id> -e geo '{"source":"PROXY"}' deviceMock
默认:关闭。 模拟设备为其他型号。设置 "enabled":true 并填写以下任意字段 — 所有字段均为可选字符串(默认为空),每个字段对应一个 Android Build 属性:
| 字段 | 对应属性 | 示例 |
|---|---|---|
manufacturer | Build.MANUFACTURER | Samsung |
brand | Build.BRAND | samsung |
model | Build.MODEL | SM-S918B |
device | Build.DEVICE (代号) | dm3q |
product | Build.PRODUCT | dm3qxxx |
board | Build.BOARD | kalama |
hardware | Build.HARDWARE | qcom |
buildId | Build.ID | UP1A.231005.007 |
buildIncremental | Build.VERSION.INCREMENTAL | S918BXXU3CWK9 |
buildType | Build.TYPE | user |
buildTags | Build.TAGS | release-keys |
buildFingerprint | Build.FINGERPRINT | samsung/dm3qxxx/dm3q:14/UP1A.231005.007/S918BXXU3CWK9:user/release-keys |
deviceName | 显示的设备名称 | Galaxy S23 Ultra |
adb shell am broadcast -a com.wowsoftware.hidemyandroid.HEADLESS_UPDATE -p com.wowsoftware.hidemyandroid -e token <your_access_token> -e id <profile_id> -e deviceMock '{"enabled":true,"manufacturer":"Samsung","brand":"samsung","model":"SM-S918B","device":"dm3q","product":"dm3qxxx","board":"kalama","hardware":"qcom","buildId":"UP1A.231005.007","buildIncremental":"S918BXXU3CWK9","buildType":"user","buildTags":"release-keys","buildFingerprint":"samsung/dm3qxxx/dm3q:14/UP1A.231005.007/S918BXXU3CWK9:user/release-keys","deviceName":"Galaxy S23 Ultra"}' sim
默认:关闭。 伪装 SIM 卡/运营商信息。设置 "enabled":true 并在 simCards 中提供最多两张 SIM 卡信息。该列表始终会被规范化为恰好两张:第三张会被静默丢弃 — 请求仍会返回 ok=true — 而只提供一张时会补上一张空白卡,因此 profile.get 始终返回两张。每张 SIM 卡包含以下字段:
| 字段 | 类型 | 默认值 | 含义 / 约束 |
|---|---|---|---|
slotIndex | int | 0 | SIM 卡槽 — 根据该卡在数组中的位置自动分配(0,然后 1);您发送的值会被忽略 |
carrierName | string | "" | 运营商名称(如 AT&T) |
countryIso | string | "" | ISO 国家代码(如 us)— 以小写形式存储。请注意这与 geo.countryCode 相反,后者以大写形式存储 |
mcc | string | "" | 移动国家代码(如 310) |
mnc | string | "" | 移动网络代码(如 410) |
operatorCode | string | "" | 运营商代码 = mcc + mnc(如 310410) |
phoneNumber | string | "" | 电话号码 |
iccid | string | "" | SIM 卡序列号(ICCID) |
imsi | string | "" | IMSI |
networkType | string | "" | 网络类型 — 请参阅下方可接受的值;无法识别的值会被静默忽略 |
networkType 会先去除首尾空格再进行不区分大小写的匹配,并且每个网络世代都接受多种写法:
| 值 | 同样接受 | 网络制式 |
|---|---|---|
NR 5G | NR, 5G | 5G |
LTE | 4G | 4G |
WCDMA | UMTS, 3G | 3G |
GSM | 2G | 2G |
⚠️ 凡是不在此表中的值都会静默关闭该卡的网络类型伪装 — 没有错误,也没有
BAD_REQUEST,该值只会被保存却从不使用。请注意NR 5G中间有一个空格:NR5G无法被识别,正好会掉进这个静默的坑里。
adb shell am broadcast -a com.wowsoftware.hidemyandroid.HEADLESS_UPDATE -p com.wowsoftware.hidemyandroid -e token <your_access_token> -e id <profile_id> -e sim '{"enabled":true,"simCards":[{"slotIndex":0,"carrierName":"AT&T","countryIso":"us","mcc":"310","mnc":"410","operatorCode":"310410","networkType":"LTE"},{"slotIndex":1,"carrierName":"T-Mobile","countryIso":"us","mcc":"310","mnc":"260","operatorCode":"310260","networkType":"NR 5G"}]}' gmails
默认:空。 虚拟 Google 账号列表 — 仅接受 @gmail.com 地址。新列表将覆盖旧列表;[] 可清空列表。由于不含 :,可直接使用 content call:
adb shell content call --uri content://com.wowsoftware.hidemyandroid.headless --method profile.update --extra token:s:<your_access_token> --extra id:s:<profile_id> --extra 'gmails:s:["alice@gmail.com","bob@gmail.com"]' 完整示例
从零开始的完整配置流程:
# 1. create a profile — copy the returned id into <profile_id> below
adb shell content call --uri content://com.wowsoftware.hidemyandroid.headless --method profile.create --extra token:s:<your_access_token> --extra name:s:Demo
# 2. add a target app
adb shell content call --uri content://com.wowsoftware.hidemyandroid.headless --method profile.addApp --extra token:s:<your_access_token> --extra id:s:<profile_id> --extra packageName:s:com.whatsapp
# 3. add the virtual Gmail accounts
adb shell content call --uri content://com.wowsoftware.hidemyandroid.headless --method profile.update --extra token:s:<your_access_token> --extra id:s:<profile_id> --extra 'gmails:s:["alice@gmail.com","bob@gmail.com"]'
# 4. enable + set the device mock
adb shell am broadcast -a com.wowsoftware.hidemyandroid.HEADLESS_UPDATE -p com.wowsoftware.hidemyandroid -e token <your_access_token> -e id <profile_id> -e deviceMock '{"enabled":true,"manufacturer":"Samsung","brand":"samsung","model":"SM-S918B","device":"dm3q","product":"dm3qxxx","board":"kalama","hardware":"qcom","buildId":"UP1A.231005.007","buildIncremental":"S918BXXU3CWK9","buildType":"user","buildTags":"release-keys","buildFingerprint":"samsung/dm3qxxx/dm3q:14/UP1A.231005.007/S918BXXU3CWK9:user/release-keys","deviceName":"Galaxy S23 Ultra"}'
# 5. enable + set the SIM mock (two cards, full fields)
adb shell am broadcast -a com.wowsoftware.hidemyandroid.HEADLESS_UPDATE -p com.wowsoftware.hidemyandroid -e token <your_access_token> -e id <profile_id> -e sim '{"enabled":true,"simCards":[{"slotIndex":0,"carrierName":"AT&T","countryIso":"us","mcc":"310","mnc":"410","operatorCode":"310410","networkType":"LTE","phoneNumber":"+12025550123","iccid":"8901410123456789012","imsi":"310410123456789"},{"slotIndex":1,"carrierName":"T-Mobile","countryIso":"us","mcc":"310","mnc":"260","operatorCode":"310260","networkType":"NR 5G","phoneNumber":"+12025550456","iccid":"8901260987654321098","imsi":"310260987654321"}]}'
# 6. enable + set the proxy (tested live, ~8s)
adb shell am broadcast -a com.wowsoftware.hidemyandroid.HEADLESS_UPDATE -p com.wowsoftware.hidemyandroid -e token <your_access_token> -e id <profile_id> -e proxy '{"enabled":true,"host":"10.0.0.1","port":1080,"protocol":"SOCKS5"}'
# 7. pick where the location comes from — geo has two sources, choose ONE
# A) from the proxy you just set. This is the default, so the line is optional:
adb shell am broadcast -a com.wowsoftware.hidemyandroid.HEADLESS_UPDATE -p com.wowsoftware.hidemyandroid -e token <your_access_token> -e id <profile_id> -e geo '{"source":"PROXY"}'
# B) or set it yourself — this needs no proxy at all. Use B *instead of* A, not after it:
# adb shell am broadcast -a com.wowsoftware.hidemyandroid.HEADLESS_UPDATE -p com.wowsoftware.hidemyandroid -e token <your_access_token> -e id <profile_id> -e geo '{"source":"CUSTOM","latitude":35.6812,"longitude":139.7671,"countryCode":"JP","timezone":"Asia/Tokyo","language":"ja"}'
# geo and proxy are independent: setting one never rewrites the other, and only
# geo.source decides which one feeds the hooks. So CUSTOM together with a proxy in
# a different country means your IP says one place while your GPS says another.
# 8. activate (restarts the target app and clears its data)
adb shell content call --uri content://com.wowsoftware.hidemyandroid.headless --method profile.setActive --extra token:s:<your_access_token> --extra id:s:<profile_id>
# 9. verify
adb shell content call --uri content://com.wowsoftware.hidemyandroid.headless --method profile.get --extra token:s:<your_access_token> --extra id:s:<profile_id> 错误代码
请求失败时返回 ok=false 并附带以下 error_code 值(广播返回 result=1):
| 代码 | 含义 | 修复方法 |
|---|---|---|
UNAUTHORIZED | Token 缺失或错误 | 使用当前有效的密钥;不确定时请重新生成 |
FEATURE_DISABLED | Headless API 未开启 | 在设置 → 开发者 → Headless API 中启用 |
BAD_REQUEST | 参数或 JSON 格式错误 | 检查必填字段、JSON 格式是否正确、是否仅使用 Gmail 地址、是否有重复应用、软件包是否属于该配置文件 |
NOT_FOUND | 该配置文件、任务或备份不存在 | 通过 profile.list、backup.job 或 backup.list 确认 id 是否正确 |
BUSY | 备份/恢复任务仍占用着执行槽位 | error_message 中给出了正在运行的 jobId — 请等待任务结束后再重试;取消之后,槽位的占用可能比 CANCELLED 状态存续得更久,因此请持续重试,直到不再返回 BUSY。当任务占用着执行槽位时,profile.setActive / deactivate / delete 也会返回此代码 |
REQUIRES_ACTIVE_PROFILE | 对未激活的配置文件调用了 backup.start / restore.start | 请先对其执行 profile.setActive — 没有任何绕过开关 |
NO_BACKUP | restore.start 找不到所请求应用的备份(或该配置文件根本没有任何备份) | 检查 backup.list;请先运行 backup.start |
PROXY_INVALID | 代理未通过实时检测 | 检查主机/端口/协议/认证信息及设备网络连接;该代理未被保存 |
LICENSE_EXPIRED | 高级版已过期 | 续订高级版 |
LICENSE_STALE | 许可证近期未在线验证 | 打开应用一次以重新验证(持续使用时至少每 24 小时验证一次) |
INTERNAL | 内部错误(I/O 或 Root 相关) | 重试;检查 Root/LSPosed 是否正常运行 |
提示与常见问题
- 广播命令没有任何效果? 请确认命令中包含了
-p com.wowsoftware.hidemyandroid— Android 会拦截不带此参数的广播。 - 值在
:后被截断? 该值包含冒号,content call会在冒号处截断。请改用HEADLESS_UPDATE广播发送该值。 - JSON 广播未生效(Windows 上常见)? 在桌面 Shell 与设备 Shell 之间传递时,
am broadcast命令中的 JSON 引号(hookFlags、proxy、deviceMock、sim)很容易被转义处理,导致am解析出错(值可能被识别为dat=…数据 URI)从而不生效。可靠的解决方法是避免在命令行中直接传入 JSON — 将整个工作流放入一个.sh文件(单引号可保留所有 JSON 内容完整),然后推送到设备上运行。脚本在 设备上 运行,因此还可以捕获新建的配置文件 id 并在后续步骤中复用:bash然后将文件推送到设备并运行:# setup.sh — the full example as one runnable script (runs on the device) URI=content://com.wowsoftware.hidemyandroid.headless PKG=com.wowsoftware.hidemyandroid K=<your_access_token> # 1. create a profile and capture its id ID=$(content call --uri $URI --method profile.create --extra token:s:$K --extra name:s:Demo | grep -o '"id":"[^"]*"' | head -n1 | sed 's/.*"id":"//;s/"//') echo "profile id: $ID" # 2. add a target app content call --uri $URI --method profile.addApp --extra token:s:$K --extra id:s:$ID --extra packageName:s:com.facebook.katana # 3. add the virtual Gmail accounts content call --uri $URI --method profile.update --extra token:s:$K --extra id:s:$ID --extra 'gmails:s:["alice@gmail.com","bob@gmail.com"]' # 4. enable + set the device mock am broadcast -a $PKG.HEADLESS_UPDATE -p $PKG -e token $K -e id $ID -e deviceMock '{"enabled":true,"manufacturer":"Samsung","brand":"samsung","model":"SM-S918B","device":"dm3q","product":"dm3qxxx","board":"kalama","hardware":"qcom","buildId":"UP1A.231005.007","buildIncremental":"S918BXXU3CWK9","buildType":"user","buildTags":"release-keys","buildFingerprint":"samsung/dm3qxxx/dm3q:14/UP1A.231005.007/S918BXXU3CWK9:user/release-keys","deviceName":"Galaxy S23 Ultra"}' # 5. enable + set the SIM mock (two cards) am broadcast -a $PKG.HEADLESS_UPDATE -p $PKG -e token $K -e id $ID -e sim '{"enabled":true,"simCards":[{"slotIndex":0,"carrierName":"AT&T","countryIso":"us","mcc":"310","mnc":"410","operatorCode":"310410","networkType":"LTE","phoneNumber":"+12025550123","iccid":"8901410123456789012","imsi":"310410123456789"},{"slotIndex":1,"carrierName":"T-Mobile","countryIso":"us","mcc":"310","mnc":"260","operatorCode":"310260","networkType":"NR 5G","phoneNumber":"+12025550456","iccid":"8901260987654321098","imsi":"310260987654321"}]}' # 6. enable + set the proxy (tested live, ~8s) am broadcast -a $PKG.HEADLESS_UPDATE -p $PKG -e token $K -e id $ID -e proxy '{"enabled":true,"host":"10.0.0.1","port":1080,"protocol":"SOCKS5"}' # 7. pick where the location comes from — geo has two sources, choose ONE # A) from the proxy you just set. This is the default, so the line is optional: am broadcast -a $PKG.HEADLESS_UPDATE -p $PKG -e token $K -e id $ID -e geo '{"source":"PROXY"}' # B) or set it yourself — this needs no proxy at all. Use B *instead of* A, not after it: # am broadcast -a $PKG.HEADLESS_UPDATE -p $PKG -e token $K -e id $ID -e geo '{"source":"CUSTOM","latitude":35.6812,"longitude":139.7671,"countryCode":"JP","timezone":"Asia/Tokyo","language":"ja"}' # geo and proxy are independent: setting one never rewrites the other, and only # geo.source decides which one feeds the hooks. So CUSTOM together with a proxy in # a different country means your IP says one place while your GPS says another. # 8. activate (restarts the target app and clears its data) content call --uri $URI --method profile.setActive --extra token:s:$K --extra id:s:$ID # 9. verify content call --uri $URI --method profile.get --extra token:s:$K --extra id:s:$IDbash不含 JSON 的普通adb push setup.sh /data/local/tmp/setup.sh adb shell sh /data/local/tmp/setup.shcontent call命令可直接在命令行输入,无需脚本。在 Git Bash 中,请在adb命令前加上MSYS_NO_PATHCONV=1,以防止设备路径被重写。 - 修改未生效? 目标应用必须重启 — 激活配置文件时会自动完成此操作,并在同一步骤中清除该应用的数据,因此它会以全新身份启动,不保留此前的任何内容。
- 信任的代理仍返回
PROXY_INVALID? 设备需要联网才能完成检测,超时上限约为 8 秒,响应较慢的代理可能会超时。 - 已取消的任务仍返回
BUSY?backup.cancel会立即将任务置为CANCELLED(并设置finishedAt),但它启动的tar无法被打断,会继续运行,因此槽位仍被占用。backup.job在槽位仍然繁忙时就已显示CANCELLED,且没有任何字段会报告槽位状态 — 请勿把CANCELLED当作「槽位已空」;只需重试profile.setActive/deactivate/delete,直到它们不再返回BUSY。(以DONE或FAILED自然结束的任务几乎会立即释放槽位。)