小米手机中自动设置「冰狐智能辅助」的相关权限

在移动端自动化脚本的实际落地过程中,权限配置往往是决定脚本能否稳定运行的首要瓶颈。尤其是小米(MIUI)等深度定制的Android系统,其独有的省电策略、自启动管理和后台限制机制,常常导致自动化服务被系统回收或功能受限。本文将深入剖析一套专为小米手机设计的自动化权限配置脚本,并给出完整可用的源码实现。

一、为什么需要自动化权限配置?

冰狐智能辅助基于Android无障碍服务实现控件识别与模拟操作。然而,小米的MIUI系统对后台应用有着严格的管控策略——省电模式会限制APP后台运行、锁屏后可能断开数据连接、自启动管理未开启则应用无法在后台被唤醒。这些限制如果未在系统设置中逐一解除,脚本执行过程中随时可能因服务被杀死而中断。

手动完成这些配置不仅繁琐,而且在不同MIUI版本和机型上路径可能略有差异。通过冰狐提供的findViewswitchPagescrollclick等API,我们可以编写脚本自动遍历系统设置界面,完成所有必要权限的一键配置。


二、脚本核心API解析

在深入源码之前,有必要了解本脚本使用到的几个核心冰狐API:

1. launchApp(packageName)

启动指定包名的应用。本脚本通过launchApp('com.android.settings')打开系统设置。

2. findView(tag, options)

根据tag查找UI控件。tag支持多种格式:

  • txt:设置 —— 查找文本为"设置"的控件

  • txt$:个应用程序 —— 查找文本以"个应用程序"结尾的控件

  • cn:miui.widget.ClearableEditText —— 按类名查找

返回值包含views数组,每个元素为node对象。

3. switchPage(fromTag, toTag, options)

从当前页面切换到目标页面。本质是在当前界面查找toTag对应的控件并点击,若找不到则返回空数组。

4. scroll(direction, options)

在屏幕上执行滚动操作。direction'up''down'distance控制滚动幅度。

5. click(view, options)

点击指定的控件节点。

6. back2Page(tag, options)

通过返回键退回到包含指定tag的页面。

7. paste(view, text, options)

向输入框粘贴文本,用于在搜索框中输入"冰狐智能辅助"的应用名称。


三、脚本功能模块详解

脚本的主流程在main()函数中,整体采用目标驱动的设计模式:

var target = 'txt:我的设备|txt:双卡和移动网络|txt:锁屏|txt:电池与性能|txt:应用设置|txt:授权管理|';

脚本依次尝试在设置主界面查找这六个目标项,每找到一个就执行对应的配置函数,然后从目标字符串中移除该项,继续查找下一个。这种设计使得脚本具有很强的容错性——即使某个配置项因MIUI版本差异而位置不同,也不会影响其他配置的执行。

模块一:update() —— 系统更新配置

该函数负责进入「我的设备」→「MIUI版本」→「系统更新设置」,关闭「自动下载」、「智能更新」、「自动更新」和「加入优先升级计划」等选项。

function update() {
    var ret = switchPage('txt:我的设备', 'txt:MIUI 版本', {click: true, failed: exitPopup});
    // ... 逐层进入并关闭自动更新相关开关
}

设计意图:系统自动更新可能在不恰当的时机重启设备或占用大量资源,导致自动化脚本中断。关闭自动更新可确保脚本运行环境的稳定性。

模块二:network() —— 移动网络配置

该函数进入「双卡和移动网络」→「启用数据网络」,确保数据网络开关处于开启状态,并关闭「始终接收彩信」以节省流量。

function network() {
    var ret = switchPage('txt:双卡和移动网络', 'txt:启用数据网络', {click: true, failed: exitPopup});
    // 检查开关状态,若未开启则点击开启
}

模块三:lockScreen() —— 锁屏配置

该函数进入「锁屏」→「自动锁屏」,将锁屏时间设置为「屏幕永不休眠」。

function lockScreen() {
    var ret = switchPage('txt:锁屏', 'txt:自动锁屏', {click: true, failed: exitPopup});
    // 若当前不是"永不",则选择"永不"选项
}

设计意图:屏幕锁屏后,部分自动化操作(尤其是涉及界面渲染和控件识别的操作)可能受到影响。保持屏幕常亮可提升脚本执行的可靠性。

模块四:performance() —— 电池与性能配置

该函数进入「电池与性能」→「省电模式」→「锁屏后断开数据」,将选项设置为「从不」。

function performance() {
    var ret = switchPage('txt:电池与性能', 'txt:省电模式', {click: true, failed: exitPopup});
    // 进入锁屏后断开数据设置,确保选择"从不"
}

设计意图:MIUI的省电策略会在锁屏后自动断开数据连接,这会导致依赖网络的自动化任务失败。将此选项设为「从不」可保证后台网络连接的持续性。

模块五:app() —— 应用权限与自启动配置

这是脚本中最复杂的模块,负责两大部分配置:

第一部分:应用权限管理

  1. 从「应用设置」进入「授权管理」→「应用权限管理」→「应用管理」

  2. 在搜索框中粘贴"冰狐智能辅助"的应用名称进行搜索

  3. 进入应用详情页,将「允许应用在锁屏上显示」和「允许应用在后台弹出界面」设置为允许

第二部分:自启动管理

  1. 返回「授权管理」页面,进入「自启动管理」

  2. 在应用列表中滚动查找"冰狐智能辅助"

  3. 找到后将开关设置为开启状态

function app(doFirst=true) {
    // 第一部分:权限管理
    var ret = switchPage('txt:应用设置', 'txt:授权管理', {click: true, failed: exitPopup});
    // ... 逐层进入,搜索应用,设置权限
    
    // 第二部分:自启动管理
    ret = switchPage('txt:自启动管理', 'txt:更多', {click: true, failed: exitPopup});
    // 在RecyclerView中遍历查找目标应用
    var container = findView('cn:androidx.recyclerview.widget.RecyclerView');
    // 遍历每个item,匹配应用名称,开启开关
}

设计意图:自启动管理是MIUI后台管控的核心机制之一。未开启自启动的应用在后台会被系统强制回收,导致无障碍服务中断。将此开关开启是保证冰狐智能辅助在后台持续运行的关键。

辅助函数:exitPopup() —— 弹窗处理

脚本在执行过程中可能遇到各种系统弹窗(如「关于自启动的说明」、「暂不开启」等),exitPopup函数作为findViewfailed回调,会在找不到目标控件时自动处理这些弹窗:

function exitPopup() {
    var ret = findView('txt:暂不开启|txt:关于自启动的说明|txt:进入首页', {maxStep:1});
    if (ret.length > 0) {
        // 点击弹窗按钮关闭它
        click(ret.views[0], {click: true, afterWait: 1000});
        return true;
    }
    return false;
}

这种弹窗自动处理机制大大增强了脚本的鲁棒性,避免了因意外弹窗导致的执行中断。

四、完整源码

function main() {
    var result = 0;

    if (!launchApp('com.android.settings')) {
        console.error('启动失败');
        return result;
    }

    var ret = findView('txt:设置', {failed: exitPopup, maxStep:50});
    if (ret.length <= 0) {
        console.error('找不到容器');
        return result;
    }

    var target = 'txt:我的设备|txt:双卡和移动网络|txt:锁屏|txt:电池与性能|txt:应用设置|txt:授权管理|', scrollCount = 0, successCount = 0;
    while (scrollCount <= 3 && target != '') {
        ret = findView(target, {failed: exitPopup});
        if (ret.length <= 0) {
            scrollCount++;
            console.log('scroll');
            scroll('up', {distance: 0.99, afterWait: 1000});
        } else {
            var text = ret.views[0].text;
            console.log('text:' + text);

            if (text == '我的设备') {
                if (update()) {
                    successCount++;
                } else {
                    result = -4;
                    console.error('我的设备设置失败');
                }
            } else if (text == '双卡和移动网络') {
                if (network()) {
                    successCount++;
                } else {
                    result = -8;
                    console.error('移动网络设置失败');
                }
            } else if (text == '锁屏') {
                if (lockScreen()) {
                    successCount++;
                } else {
                    result = -5;
                    console.error('锁屏设置失败');
                }
            } else if (text == '电池与性能') {
                if (performance()) {
                    successCount++;
                } else {
                    result = -6;
                    console.error('电池与性能失败');
                }
            } else if (text == '应用设置') {
                target = target.replace('授权管理|', '');
                result = app();
                if (result == 1) {
                    successCount++;
                }
            } else if (text == '授权管理') {
                target = target.replace('应用设置|', '');
                result = app(false);
            }

            target = target.replace(text+'|', '');
        }
    }

    if (successCount == 4) {
        result = 1;
    }

    console.log('end:' + result);

    exitAppDeal();

    return result;
}

function app(doFirst=true) {
    var result = -7, success = true;
    if (doFirst) {
        var ret = switchPage('txt:应用设置', 'txt:授权管理', {click: true, failed: exitPopup});
        success = ret.length > 0;
    }

    if (success) {
        var ret = switchPage('txt:授权管理', 'txt:应用权限管理', {click: true, failed: exitPopup});
        if (ret.length > 0) {
            ret = switchPage('txt:应用权限管理', 'txt:应用管理', {click: true, failed: exitPopup});
            if (ret.length > 0) {
                ret = findView('txt$:个应用程序');
                if (ret.length > 0) {
                    click(ret.views[0], {click: true});
                    ret = findView('cn:miui.widget.ClearableEditText');
                    if (ret.length > 0) {
                        console.log('do paste:' + getAppName());
                        paste(ret.views[0], getAppName(), {type: 'paste', afterWait: 4000});

                        var container = findView('cn:androidx.recyclerview.widget.RecyclerView');
                        if (container.length > 0 && container.views[0].size > 0) {
                            console.log('click sub item');
                            click(container.views[0][0], {click: true, afterWait: 1000});
                            scroll('up', {distance: 0.99, afterWait: 1000});

                            if (setAppPermission('允许应用在锁屏上显示')) {
                                if (setAppPermission('允许应用在后台弹出界面')) {
                                    result = 1;
                                } else {
                                    console.log('设置 允许应用在后台弹出界面失败');
                                }
                            } else {
                                console.log('设置 锁屏上显示应用失败');
                            }
                        } else {
                            console.log('can not find recyclerView:' + container.views[0].size);
                        }
                    } else {
                        console.log('can not find edit');
                    }
                }

                if (result == 1) {
                    result = -2;
                    if (back2Page('txt:授权管理', {failed: exitPopup})) {
                        ret = switchPage('txt:自启动管理', 'txt:更多', {click: true, failed: exitPopup});
                        if (ret.length > 0) {
                            console.log('start find');
                            var container = findView('cn:androidx.recyclerview.widget.RecyclerView', {failed: exitPopup});
                            var count = 0, appName = getAppName();
                            while (container.views[0].size > 0 && count < 20) {
                                var find = false;
                                for (var item of container.views[0]) {
                                    if (item[1].className=='android.widget.TextView' && item[1].text==appName) {
                                        if (!item[2].checked) {
                                            click(item[2], {click:true});
                                        }
                                        find = true;
                                        break;
                                    } else if (item[1][0][0].className=='android.widget.TextView' && item[1][0][0].text==appName) {
                                        if (!item[2].checked) {
                                            click(item[2], {click: true});
                                        }
                                        find = true;
                                        break;
                                    }
                                }

                                if (find) {
                                    console.log('ok----');
                                    result = 1;
                                    break;
                                }

                                console.log('scroll--');
                                count ++;
                                scroll('up', {root: container.views[0], type: 2, afterWait:1000});

                                container = findView('cn:androidx.recyclerview.widget.RecyclerView', {failed: exitPopup});
                            }
                        } else {
                            console.error('进入自启动失败');
                        }
                    } else {
                        console.log('没有进入授权管理');
                    }
                }
            } else {
                console.log('没进入  应用管理');
            }
        }
    }

    return result;
}

function setAppPermission(itemName) {
    var result = false;
    var ret = findView('txt:' + itemName, {maxStep: 6});
    if (ret.length > 0) {
        console.log('找到 锁屏显示');
        if (ret.views[0].parent.parent[1].text == '拒绝') {
            ret = switchPage('txt:' + itemName, 'txt:取消', {click: true, failed: exitPopup});
            if (ret.length > 0) {
                ret = findView('txt:始终允许|txt:允许');
                if (ret.length > 0) {
                    click(ret.views[0], {click: true, afterWait: 2000});
                    result = true;
                }
            }
        } else {
            result = true;
            console.log('已经不是拒绝,所以不再');
        }
    } else {
        console.error('无法找到:' + itemName);
    }

    return result;
}

function performance() {
    var result = false;

    var ret = switchPage('txt:电池与性能', 'txt:省电模式', {click: true, failed: exitPopup});
    if (ret.length > 0) {
        ret = switchPage('txt:设置', 'txt:锁屏后断开数据', {click: true, failed: exitPopup});
        if (ret.length > 0) {
            if (ret.views[0].parent.parent[1][0][0][0].text!='从不') {
                ret = switchPage('txt:锁屏后断开数据', 'txt:30分钟后', {click: true, failed: exitPopup});
                if (ret.length > 0) {
                    click(ret.views[0].parent.parent.parent.parent.parent[3], {click: true});
                    result = true;
                }
            } else {
                result = true;
            }
        } else {
            console.log('找不到 锁屏后断开数据');
        }

        back2Page('txt:隐私保护|txt:锁屏', {failed: exitPopup});
    } else {
        console.log('进入性能失败');
    }

    return result;
}

function update() {
    var result = false;
    var ret = switchPage('txt:我的设备', 'txt:MIUI 版本', {click: true, failed: exitPopup});
    if (ret.length > 0) {
        ret = switchPage('txt:MIUI 版本', 'txt:菜单|txt:发现新版本', {click: true, failed: exitPopup});
        if (ret.length > 0) {
            if (ret.tag == '菜单') {
                ret = switchPage('txt:菜单', 'txt:系统更新设置', {click: true, failed: exitPopup});
                if (ret.length > 0) {
                    ret = switchPage('txt:系统更新设置', 'txt:自动下载', {click: true, failed: exitPopup});
                    if (ret.length > 0) {
                        if (ret.views[0].parent.parent[1][0].checked) {
                            click(ret.views[0], {click: true, afterWait: 1000});
                        }

                        ret = findView('txt:智能更新');
                        if (ret.length > 0 && ret.views[0].parent.parent[1][0].checked) {
                            click(ret.views[0], {click: true, afterWait: 1000});
                        }

                        ret = findView('txt:自动更新');
                        if (ret.length > 0 && ret.views[0].parent.parent[1][0].checked) {
                            click(ret.views[0], {click: true, afterWait: 1000});
                        }

                        ret = findView('txt:加入优先升级计划');
                        if (ret.length > 0 && ret.views[0].parent.parent[1][0].checked) {
                            click(ret.views[0], {click: true, afterWait: 1000});
                        }

                        result = true;
                    } else {
                        console.log('找不到自动下载');
                    }
                } else {
                    console.log('找不到系统更新设置');
                }
            } else {
                console.log('直接找到 发现新版本');
                result = true;
            }
        } else {
            console.log('进入设置失败');
        }

        back2Page('txt:蓝牙', {failed: exitPopup});
    } else {
        console.log('进入我的失败');
    }

    return result;
}

function network() {
    var result = false;

    var ret = switchPage('txt:双卡和移动网络', 'txt:启用数据网络', {click: true, failed: exitPopup});
    if (ret.length > 0) {
        if (ret.views[0].parent.parent[1][0].checked) {
            click(ret.views[0], {click: true, afterWait: 1000});

            ret = findView('txt:始终接收彩信');
            if (ret.length > 0 && ret.views[0].parent.parent[1][0].checked) {
                click(ret.views[0], {click: true, afterWait: 1000});
            }

            result = true;
        }

        back2Page('txt:蓝牙', {failed: exitPopup});
    }

    return result;

}

function lockScreen() {
    var result = false;
    var ret = switchPage('txt:锁屏', 'txt:自动锁屏', {click: true, failed: exitPopup});
    if (ret.length > 0) {
        if (ret.views[0].parent.parent[1][0][0].text!='屏幕永不休眠') {
            ret = switchPage('txt:自动锁屏', 'txt:永不', {click: true, failed: exitPopup});
            if (ret.length > 0) {
                click(ret.views[0], {click: true});
                result = true;
            }
        } else {
            result = true;
        }
        back2Page('txt:蓝牙', {failed: exitPopup});
    }
    return result;
}

function exitPopup() {
    var ret = findView('txt:暂不开启|txt:关于自启动的说明|txt:进入首页', {maxStep:1});
    if (ret.length > 0) {
        console.log('text:' + ret.tag);
        if (ret.views[0].text == '关于自启动的说明') {
            clickByTag('txt:确定', {click: true});
        } else {
            click(ret.views[0], {click: true, afterWait: 1000});
        }
        return true;
    }
    return false;
}

五、总结

本文通过一个完整的冰狐智能辅助自动化脚本,展示了如何利用平台提供的findViewswitchPagescrollclick等原生API,在小米手机上自动完成系统更新、移动网络、锁屏、电池性能、应用权限和自启动管理等六大类权限配置。

脚本的核心设计思路可以概括为三点:目标驱动的逐项配置(通过动态维护目标字符串)、弹窗的自动容错处理(通过failed回调机制)、多层级的页面导航(通过switchPageback2Page的组合使用)。这种设计模式不仅适用于小米手机的权限配置,稍作修改即可适配其他品牌Android设备的系统设置自动化。

在实际使用中,建议先在冰狐智能辅助的在线调试环境中逐段运行脚本,观察控件的查找和点击是否准确——不同MIUI版本可能在界面布局上存在细微差异,需要根据实际情况微调findView的tag参数。权限配置完成后,冰狐智能辅助即可在后台稳定运行,为后续的自动化任务提供可靠的环境保障。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值