小米手机中自动清理长时间未使用App

一、背景与需求

手机使用时间长了,总会积累大量长期不用的App。它们占据存储空间、在后台消耗资源、推送无用的通知,拖累手机的整体运行效率。手动逐个检查“哪些App很久没用过”是一项繁琐且耗时的工作,尤其当手机里装了上百个应用时。

小米手机的安全中心内置了“应用卸载”功能,能够按照“使用频率”对已安装应用进行排序,并标注“未使用”状态。这个功能为自动化清理提供了基础——我们只需要用脚本自动识别这些“未使用”的应用,批量勾选并一键卸载即可。

冰狐智能辅助平台提供了完善的无障碍自动化API,允许开发者通过JavaScript脚本操控Android应用的UI控件。本文将基于冰狐平台的launchAppfindViewclickswitchPage等核心API,深入解析如何编写一个自动清理小米手机中长期未使用App的脚本。

二、整体设计思路

脚本的核心逻辑分为以下几个步骤:

  1. 启动小米安全中心——通过launchApp函数启动指定包名的应用。

  2. 导航到应用卸载页面——依次点击“应用管理”→“应用卸载”。

  3. 切换到“使用频率”排序——默认可能是按“存储占用”排序,需要切换到“使用频率”,让“未使用”的应用排在前面。

  4. 遍历应用列表——获取RecyclerView容器,逐个检查每个应用项是否标记为“未使用”,同时检查是否在白名单中。

  5. 批量卸载——勾选所有符合条件的应用,点击“一键卸载”,等待卸载完成。

白名单机制用于保护重要应用不被误删,例如微信、支付宝等日常必备工具。

三、核心API解析

在深入源码之前,先简要介绍脚本中用到的几个核心冰狐API:

launchApp(packageName) :通过应用包名启动指定App。返回true表示启动成功,false表示失败。

findView(tag, options) :通过控件的text、id、className等属性查找UI控件。返回值为JSON对象,包含tagviews两个属性,views为找到的控件节点数组。支持txt:(文本匹配)、cn:(类名匹配)、id:(ID匹配)等多种匹配方式。可通过maxStep参数控制最大查找步数。

click(tag, options) :点击控件。支持传入控件对象或tag字符串,可配置click(是否使用原生点击)、afterWait(点击后等待时间)等参数。

switchPage(findTag, checkTag, options) :切换页面。先查找findTag对应的控件并点击,然后检查checkTag对应的控件是否出现来判断页面切换是否成功。返回对象的length大于0表示成功。

console.log() 和 console.error() :输出日志,用于调试和记录执行状态。

四、源码实现

// 删除长时间没有使用的app,系统app和白名单中的app不删除
function main(whiteList=[]) {
    // 1. 启动小米安全中心
    if (!launchApp('com.miui.securitycenter')) {
        return;
    }

    var ret = findView('txt:安全中心', {maxStep: 30});
    if (ret.length <= 0) {
        console.log('启动安全中心失败');
        return;
    }

    // 2. 添加默认白名单应用
    whiteList.push('微信');
    whiteList.push('支付宝');

    // 3. 进入应用管理 -> 应用卸载
    ret = switchPage('txt:应用管理', 'txt:应用卸载', {click: true});
    if (ret.length > 0) {
        ret = switchPage('txt:应用卸载', 'txt^:卸载选中应用|txt^:一键卸载', {click: true});
        if (ret.length > 0) {
            // 4. 切换到“使用频率”排序
            ret = findView('txt:存储占用|txt:使用频率|txt:安装时间');
            if (ret.length > 0) {
                if (ret.tag != '使用频率') {
                    click(ret.views[0], {click: true, afterWait: 1000});
                    ret = findView('txt:使用频率');
                    if (ret.length > 0) {
                        click(ret.views[0], {click: true, afterWait: 1000});
                    }
                }

                // 5. 遍历应用列表,勾选“未使用”且不在白名单中的应用
                var selectedCount = 0, index = 0;
                var container = findView('cn:androidx.recyclerview.widget.RecyclerView');
                while (container.length > 0 && index < container.views[0].size) {
                    var item = container.views[0][index];
                    
                    // 适配不同的UI布局结构
                    if (item[0].size == 4) {
                        // 布局结构1:item有4个子控件
                        if (item[0][1][1].text.includes('未使用')) {
                            if (!item[0][3][0].checked) {
                                if (whiteList.indexOf(item[0][1][0].text) < 0) {
                                    click(item, {click: true});
                                    selectedCount++;
                                }
                            }
                        } else {
                            break;  // 遇到非“未使用”的应用则停止遍历
                        }
                    } else if (item[0].size == 3 && item[0][1].size == 3) {
                        // 布局结构2:item有3个子控件,其中第二个子控件有3个子控件
                        console.log('item[0][1][2].text:' + item[0][1][2].text);
                        if (item[0][1][2].text.includes('未使用')) {
                            if (!item[0][2].checked) {
                                console.log('txt:' + item[0][1][0].text);
                                if (whiteList.indexOf(item[0][1][0].text) < 0) {
                                    click(item[0], {click:true});
                                    selectedCount++;
                                }
                            }
                        } else {
                            break;
                        }
                    } else {
                        console.log('忽略一个item');
                    }

                    ++index;
                    container = findView('cn:androidx.recyclerview.widget.RecyclerView');
                }

                // 6. 如果有勾选的应用,执行批量卸载
                if (selectedCount > 0) {
                    ret = switchPage('txt^:卸载选中应用|txt^:一键卸载', 'txt:确定|txt:卸载选中应用', {click: true});
                    if (ret.length > 0) {
                        click(ret.views[0], {click: true, afterWait: 3000});

                        var startTime = new Date().getTime();
                        ret = findView('txt:应用卸载');
                        while (ret.length <= 0 && (new Date().getTime() - startTime) < 120000) {
                            ret = findView('txt:应用卸载', {afterWait: 1000});
                        }
                        console.log('卸载成功');
                    }
                } else {
                    console.log('没有需要卸载的');
                }
            }
        }
    } else {
        console.error('进入优化加速失败');
    }
}

五、源码逐段解析

5.1 启动安全中心

if (!launchApp('com.miui.securitycenter')) {
    return;
}

com.miui.securitycenter是小米安全中心的应用包名。launchApp如果返回false,说明应用不存在或无法启动,脚本直接退出。

5.2 确认安全中心已启动

var ret = findView('txt:安全中心', {maxStep: 30});
if (ret.length <= 0) {
    console.log('启动安全中心失败');
    return;
}

通过查找“安全中心”文本控件来确认页面已加载完成。maxStep: 30表示最多尝试30步(每步约几百毫秒),给页面加载留出足够时间。

5.3 页面导航

ret = switchPage('txt:应用管理', 'txt:应用卸载', {click: true});

switchPage是冰狐提供的高阶页面切换函数。它会先查找“应用管理”控件并点击,然后等待“应用卸载”控件出现。如果两个条件都满足,说明页面切换成功。{click: true}表示使用控件原生的点击功能。

5.4 切换到“使用频率”排序

ret = findView('txt:存储占用|txt:使用频率|txt:安装时间');

这里使用|分隔多个匹配条件,查找排序标签。如果当前选中的不是“使用频率”,则点击当前标签弹出排序选项,再点击“使用频率”。

5.5 遍历应用列表——核心逻辑

这是脚本最复杂的部分。小米应用卸载页面的应用列表是一个RecyclerView容器。每个应用项是一个控件节点,我们需要遍历所有子项:

var container = findView('cn:androidx.recyclerview.widget.RecyclerView');
while (container.length > 0 && index < container.views[0].size) {
    var item = container.views[0][index];
    // 处理每个item...
    ++index;
    container = findView('cn:androidx.recyclerview.widget.RecyclerView');
}

每次循环结束后重新获取container,是因为UI可能在滚动或刷新后发生变化。

为什么有两种布局结构判断?

不同版本的小米MIUI系统,应用卸载页面的控件布局结构可能不同。脚本通过判断item[0].size来适配两种常见布局:

  • 布局结构1 (item[0].size == 4):应用名称在item[0][1][0].text,状态标签在item[0][1][1].text,复选框在item[0][3][0].checked

  • 布局结构2 (item[0].size == 3 && item[0][1].size == 3):状态标签在item[0][1][2].text,复选框在item[0][2].checked

判断“未使用” :通过检查text.includes('未使用')来识别长期未使用的应用。

白名单过滤whiteList.indexOf(item[0][1][0].text) < 0确保白名单中的应用不被选中。

提前终止:由于列表按使用频率排序,“未使用”的应用排在最前面。一旦遇到非“未使用”的应用,说明后面的应用都是最近使用过的,直接break退出循环,提高效率。

5.6 执行卸载

ret = switchPage('txt^:卸载选中应用|txt^:一键卸载', 'txt:确定|txt:卸载选中应用', {click: true});

txt^:表示前缀匹配。不同MIUI版本中按钮文本可能是“卸载选中应用”或“一键卸载”,用前缀匹配可以兼容两种写法。

点击卸载按钮后,脚本等待卸载完成:

var startTime = new Date().getTime();
ret = findView('txt:应用卸载');
while (ret.length <= 0 && (new Date().getTime() - startTime) < 120000) {
    ret = findView('txt:应用卸载', {afterWait: 1000});
}

这里设置120秒超时(120000毫秒),每1秒检查一次“应用卸载”页面是否重新出现,以此判断卸载过程是否结束。

六、使用与扩展

调用方式

// 使用默认白名单(微信、支付宝)
main();

// 自定义白名单
main(['微信', '支付宝', '抖音', '淘宝']);

扩展建议

  1. 动态获取白名单:可以从配置文件或网络接口读取白名单,避免每次修改脚本。

  2. 增加日志记录:记录卸载了哪些应用,便于后续审计。

  3. 定时执行:结合冰狐平台的定时任务功能,每周自动执行一次清理。

  4. 异常处理增强:增加更多try-catch和重试机制,提高脚本鲁棒性。

七、注意事项

  1. 无障碍权限:冰狐智能辅助需要开启无障碍服务权限才能正常运行。

  2. MIUI版本差异:不同MIUI版本的应用卸载页面布局可能有差异,建议在目标设备上先通过“UI树”工具查看控件结构。

  3. 系统应用保护:小米安全中心的应用卸载功能本身不会列出不可卸载的系统应用,因此无需额外过滤。

  4. 执行环境:脚本需要在冰狐智能辅助移动端执行,确保设备在线且脚本已设为默认脚本。

八、总结

本文基于冰狐智能辅助平台,实现了一个自动清理小米手机中长期未使用App的脚本。通过launchApp启动应用、findView定位控件、switchPage导航页面、click模拟点击,配合RecyclerView遍历和布局适配,实现了从“打开安全中心”到“批量卸载完成”的全流程自动化。

冰狐智能辅助以JavaScript作为统一脚本语言,封装了完善的无障碍操作API,让开发者无需处理Android底层无障碍服务的复杂逻辑,即可快速实现各类自动化场景。本文的脚本可直接在小米手机上运行,有效帮助用户清理存储空间、提升手机运行效率。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值