power_manager 电源管理
约 1271 字大约 4 分钟
power_manager 电源管理
power_manager 是 ScriptX 里专门处理电池优化白名单的模块对象。当前这一组能力不多,但它有两个很容易被写糊涂的点:
- 模块名现在就是
power_manager,不是powerManager。 requestIgnoreBatteryOptimizations(...)不是只有一种参数形态,它现在同时支持“直接传包名”和“先传 forceRequest 再传包名”。
先记住这 6 条
- 当前全局对象名只有
power_manager,文档里也按这个名字写。 power_manager.isIgnoringBatteryOptimizations()不传包名时,会优先查当前脚本绑定的目标包。power_manager.requestIgnoreBatteryOptimizations()在 Android 6 以下会直接返回true,因为系统本来就没有这套电池优化白名单机制。power_manager.requestIgnoreBatteryOptimizations()会先尝试跳到“指定包的忽略电池优化授权页”;如果系统不支持,再退回到总设置页。requestIgnoreBatteryOptimizations(false, pkg)和requestIgnoreBatteryOptimizations(pkg)的效果接近,但前者把“这是 forceRequest 开关位”写得更明确。- 这组 API 只负责查询和拉起系统页面,不会替你静默授予权限。
power_manager.isIgnoringBatteryOptimizations(packageName?)
判断某个包当前是否已经在系统“忽略电池优化”白名单里。
参数
| 参数 | 类型 | 可填值 | 默认值 | 说明 |
|---|---|---|---|---|
packageName | string | 任意包名字符串 | 省略时自动推断 | 为空白字符串时会按“未传”处理 |
默认取包顺序
如果你没有显式传 packageName,当前实现会按下面这个顺序找:
- 你传入的包名
- 当前脚本运行时的
lpparam.packageName - 当前可用
Context自己的packageName
这意味着最常见的模块脚本里,直接写:
power_manager.isIgnoringBatteryOptimizations();
通常查的就是“当前被 Hook 的那个目标包”。
返回值
boolean
真实行为
- Android 6 以下:直接返回
true - 拿不到
PowerManager:返回false - 推断不出包名:返回
false - 系统调用异常:返回
false
示例
const ignored = power_manager.isIgnoringBatteryOptimizations();
log(`target ignored = ${ignored}`);
const hostIgnored = power_manager.isIgnoringBatteryOptimizations("com.tencent.mm");
log(`wechat ignored = ${hostIgnored}`);
const bogus = power_manager.isIgnoringBatteryOptimizations("com.example.not.exists");
log(`bogus package => ${bogus}`);
power_manager.requestIgnoreBatteryOptimizations(...)
拉起系统页面,引导用户把某个包加入“忽略电池优化”白名单。
这一个 API 支持的调用形态
| 写法 | 含义 |
|---|---|
power_manager.requestIgnoreBatteryOptimizations() | 针对当前目标包发起请求 |
power_manager.requestIgnoreBatteryOptimizations("com.tencent.mm") | 针对指定包发起请求 |
power_manager.requestIgnoreBatteryOptimizations(true) | 即使当前已经在白名单里,也强制再跳一次请求页 |
power_manager.requestIgnoreBatteryOptimizations(true, "com.tencent.mm") | 强制对指定包发起请求 |
参数解析规则
当前源码对前两个参数的解释是这样的:
| 第 1 个参数 | 第 2 个参数 | 实际解释 |
|---|---|---|
boolean | string? | 第 1 个参数当 forceRequest,第 2 个参数当包名 |
string | 任意 | 第 1 个参数直接当包名;第 2 个参数此时不会再参与包名解析 |
| 其他 / 不传 | string? | forceRequest = false,包名看第 2 个参数或默认包 |
也就是说,下面这两种都能用:
power_manager.requestIgnoreBatteryOptimizations("com.tencent.mm");
power_manager.requestIgnoreBatteryOptimizations(true, "com.tencent.mm");
但语义不完全一样:
- 第一种:如果已经在白名单里,通常直接返回
true - 第二种:就算已经在白名单里,也会尽量重新拉起系统授权页
返回值
boolean
返回 true 代表什么
下面几种情况都会返回 true:
- Android 6 以下,本来就不需要处理
forceRequest = false,而目标包已经在白名单里- 成功拉起了“忽略电池优化”单包授权页
- 单包页拉起失败,但成功拉起了系统总设置页
返回 false 代表什么
通常是下面几类原因:
- 推断不出要处理的包名
- 当前上下文连系统设置页都拉不起来
- 系统限制导致两次
startActivity(...)都失败
它实际会尝试打开哪两个页面
当前实现是两步退让:
- 先尝试
Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS - 如果这一步失败,再尝试
Settings.ACTION_IGNORE_BATTERY_OPTIMIZATION_SETTINGS
所以你会看到有时直接跳到“这个包是否忽略电池优化”的确认页,有时会退回系统总设置页。
示例
const ok = power_manager.requestIgnoreBatteryOptimizations();
log(`request launched = ${ok}`);
if (!power_manager.isIgnoringBatteryOptimizations()) {
const opened = power_manager.requestIgnoreBatteryOptimizations();
log(`settings opened = ${opened}`);
}
power_manager.requestIgnoreBatteryOptimizations(true, "com.tencent.mm");
什么时候适合先查再跳
最稳的写法通常是先查状态,再决定要不要跳设置页:
const pkg = lpparam.packageName;
const ignored = power_manager.isIgnoringBatteryOptimizations(pkg);
if (!ignored) {
toast("请把目标应用加入忽略电池优化白名单");
power_manager.requestIgnoreBatteryOptimizations(pkg);
}
这样做的好处是:
- 用户已经配置过时,不会每次都被强行带去设置页
- 你能把“是没配权限,还是别的问题”分开判断
适合搭配哪些场景
- 常驻监听
- 长时间定时任务
- 需要尽量减少后台被系统杀掉的脚本
- 配合
threads、events、httpServer这类会持续驻留一段时间的能力
一个新手最容易忽略的点
power_manager.requestIgnoreBatteryOptimizations(...) 只表示“页面有没有成功拉起来”,不表示“用户一定已经点了允许”。
也就是说,下面这两件事不要混为一谈:
requestIgnoreBatteryOptimizations(...)返回了true- 目标包真的已经进入白名单
如果你要做更稳的引导,拉起设置页之后最好再查一次:
power_manager.requestIgnoreBatteryOptimizations();
sleep(1500);
log(power_manager.isIgnoringBatteryOptimizations());
