diff --git a/.eslintrc.js b/.eslintrc.js index 57d0234..35c7e4a 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -35,7 +35,6 @@ module.exports = { YuvImage: true, ImageFormat: true, ui: true, - activity: true, View: true, context: true, ObjectAnimator: true, @@ -75,7 +74,6 @@ module.exports = { images: true, launchApp: true, Bitmap: true, - className: true, Buffer: true, idEndsWith: true, textEndsWith: true, diff --git a/.gitignore b/.gitignore index f023c6c..4860584 100644 --- a/.gitignore +++ b/.gitignore @@ -197,3 +197,5 @@ $RECYCLE.BIN/ # Custom rules (everything added below won't be overriden by 'Generate .gitignore File' if you use 'Update' option) + +window_dump.xml diff --git a/README.md b/README.md index e4c56ab..228e093 100644 --- a/README.md +++ b/README.md @@ -3,15 +3,18 @@ MIUI广告清理工具 ## 使用方法 -- 下载并安装[小米手机助手](http://zhushou.xiaomi.com/)或其他手机助手,确保助手可正常连接手机 -- 按手机助手的提示图文,打开手机的[USB调试模式](https://www.bilibili.com/video/BV1Ht4y1X75e) -- 打开手机的`USB安装`选项,或者自行将`MiuiCleaner.apk`安装到手机 -- `MiuiCleaner.cmd`放在手机助手的安装目录运行 -- 在手机端打开`MiuiCleaner`,点击要执行的清理项目 -## 预装应用卸载 +- [点击下载最新版本MiuiCleaner](https://github.com/gucong3000/MiuiCleaner/releases/latest),将`MiuiCleaner.apk`安装到手机即可 +- 使用“预装应用卸载”功能能时,需要root权限或者ADB权限(亦即“开发者选项”中“USB 调试”),未root用户在使用该功能时请在电脑上按以下步骤操作: + - 下载并安装[小米手机助手](http://zhushou.xiaomi.com/)、其他手机助手、或者[Android SDK 平台工具](https://developer.android.google.cn/studio/releases/platform-tools?hl=zh-cn) + - `MiuiCleaner`手机版在需要ADB权限时会自动打开手机的“开发者选项”和“USB 调试”,这时用数据线连接电脑和手机,将`MiuiCleaner.cmd`放在手机助手的安装目录运行即可。 -勾选你想要卸载的APP,点击确定就可以一键删除了。支持以下应用的卸载: +## 功能介绍 +### 预装应用卸载 + +勾选你想要卸载的APP,点击确定就可以一键删除了。支持以下62款应用的卸载: +
+点击查看详细名单 - APP 外置开屏广告 - 广告分析 @@ -88,8 +91,13 @@ MIUI广告清理工具 - 小爱视觉(扫一扫) - 小爱翻译 - 小爱通话(AI虚拟助手) +
+ +### 去广告应用 -## 去广告应用 +内置多款去广告应用的下载链接: +
+点击查看详细名单 - [李跳跳](https://www.123pan.com/s/A6cA-edAJh) > 广告自动跳过工具 @@ -108,7 +116,7 @@ MIUI广告清理工具 - [知乎](https://423down.lanzouo.com/b0f2lkafe) > 集成“知了”,可在“知了”中关闭所有广告 - [哔哩哔哩](https://423down.lanzouv.com/b0f1gksne) - > 集成“哔哩漫游”,可在“哔哩漫游”中关闭所有广告 + > 集成“哔哩漫游”,可在“哔哩漫游”中关闭所有广告(需点击其版本号7次) - [优酷视频](https://423down.lanzouv.com/b0f1avpib) > 修改版,去广告 - [百度贴吧](https://423down.lanzouv.com/b0f1b6q8d) @@ -118,14 +126,25 @@ MIUI广告清理工具 - [AppShare](https://appshare.muge.info/) > 应用商店,可下载MIUI国际版中提取的APP -## 关闭各应用广告 +
+ +### 关闭各应用广告 -支持在以下16款应用中,自动搜索到广告开关的具体位置并自动给与处置。 +支持在以下17款应用中,自动搜索50多个广告开关的具体位置,并自动给予处置。 +
+点击查看详细名单 - 小米帐号: - 关于小米帐号: - 系统广告: - 系统工具广告: `关闭` +- 系统安全: + - "加入“用户体验改进计划”": `关闭`, + - 自动发送诊断数据: `关闭` + - 广告服务: + - 个性化广告推荐: `关闭`, + - 网页链接调用服务: + - 网页链接调用服务: `关闭`, - 手机管家: - 在通知栏显示: `关闭` - 在线服务: `关闭` @@ -222,7 +241,25 @@ MIUI广告清理工具 - 通知栏快捷入口: `关闭` - Facebook快捷通知: `关闭` -### 常见问题 +
+ +[演示视频:MiuiCleaner新功能演示-广告全自动关闭](https://www.zhihu.com/zvideo/1555993019102552064) +### 应用管家 + +- 自启动管理 + > 可管理所有应用的自启动权限 +- 通知管理 + > 可以将所有通知栏广告一网打尽 +- 应用卸载 + > 可批量卸载第三方应用 +- 应用信息 + > 管理各种权限 + +### 回收站 + +你可以在这里重新安装已卸载的预装应用 + +## 常见问题 - 电脑连不上手机,咋办? > 确保数据线正常,确保驱动安装正常,可以用“360手机助手”等工具自动安装 - 删错了“XXX”,咋恢复? @@ -230,6 +267,19 @@ MIUI广告清理工具 ## CHANGELOG +- current + - PC端修复bug #1 + - 预装应用卸载 + - 修正:卸载多个应用时报“超时”的bug + - 新增:无`USB调试`权限时,自动获取授权的功能 + - 关闭各应用广告 + - 增强:小米帐号 按需显示 + - 新增:系统安全 按需显示 + - 新增:广告服务 按需显示 + - 应用管家 + - 新增:自启动管理 + - 新增:应用卸载 + - 删除:应用管理 - v2022.9.21.4 - 新增手机端 GUI - 新增广告全自动关闭功能 @@ -261,15 +311,3 @@ MIUI广告清理工具 - 提供若干内置APP卸载和恢复功能 - 提供第三方APP替换功能 -## 应用管家 - -- 通知管理 - > 可以将所有通知栏广告一网打尽 -- 应用管理 - > 可以批量卸载非预装应用 -- 应用信息 - > 管理各种权限 - -## 回收站 - -你可以在这里重新安装已卸载的预装应用 diff --git a/build.cmd b/build.cmd deleted file mode 100644 index 1590a25..0000000 --- a/build.cmd +++ /dev/null @@ -1,11 +0,0 @@ -CHCP 65001 -.\bin\Bat_To_Exe_Converter.exe ^ -/bat .\src\main.cmd ^ -/exe .\dist\MiuiCleaner.exe ^ -/ico .\favicon.ico ^ -/productversion "2022.9.10.2" ^ -/productname MiuiCleaner ^ -/description "MIUI广告清理工具" ^ -/copyright GuCong ^ -/overwrite ^ -/upx ^ diff --git a/package.json b/package.json index a8d39ef..a7aea31 100644 --- a/package.json +++ b/package.json @@ -8,7 +8,7 @@ "test:fix": "npm run test -- --fix", "start": "npx webpack --config webpack.config.js --watch --mode=development", "build:app": "npx webpack --config webpack.config.js --mode=production", - "build:cmd": "mkdir -p dist/miui_cleaner_cmd && (cat src/miui_cleaner_cmd/main.cmd | iconv --from-code=utf-8 --to-code=gbk > dist/miui_cleaner_cmd/main.cmd)", + "build:cmd": "mkdir -p dist/miui_cleaner_cmd && (cat src/miui_cleaner_cmd/main.cmd | iconv --from-code=utf-8 --to-code=gbk > dist/miui_cleaner_cmd/MiuiCleaner.cmd)", "build:pull": "adb pull /sdcard/auto.js/miui_cleaner_app/dist/MiuiCleaner_v2022.9.21.4.apk ./dist/miui_cleaner_app/", "build": "node project.js && npm run build:app && npm run build:cmd", "deploy:clear": "rm -rf ./dist/miui_cleaner_app/*.map && rm -rf ./dist/miui_cleaner_app/*.apk", diff --git a/res/MiuiPackageInstaller.apk b/res/MiuiPackageInstaller.apk new file mode 100644 index 0000000..a67f9ad Binary files /dev/null and b/res/MiuiPackageInstaller.apk differ diff --git a/res/logo.png b/res/logo.png deleted file mode 100644 index 992f5e4..0000000 Binary files a/res/logo.png and /dev/null differ diff --git a/src/miui_cleaner_app/appManager.js b/src/miui_cleaner_app/appManager.js index 608fad8..4b43f3c 100644 --- a/src/miui_cleaner_app/appManager.js +++ b/src/miui_cleaner_app/appManager.js @@ -1,32 +1,44 @@ const startActivity = require("./startActivity"); module.exports = [ + { + name: "自启动管理", + packageName: "com.miui.securitycenter", + className: "com.miui.permcenter.autostart.AutoStartManagementActivity", + }, { name: "通知管理", - fn: () => { - return startActivity({ - packageName: "com.miui.notification", - className: "miui.notification.management.activity.NotificationAppListActivity", - }); - }, + packageName: "com.miui.notification", + className: "miui.notification.management.activity.NotificationAppListActivity", }, + // { + // name: "应用管理", + // packageName: "com.miui.securitycenter", + // className: "com.miui.appmanager.AppManagerMainActivity", + // }, + // { + // name: "应用升级", + // packageName: "com.xiaomi.market", + // className: ".ui.UpdateListActivity", + // }, { - name: "应用管理", - fn: () => { - return startActivity({ - packageName: "com.miui.securitycenter", - className: "com.miui.appmanager.AppManagerMainActivity", - }); - }, + name: "应用卸载", + packageName: "com.miui.cleanmaster", + className: "com.miui.optimizecenter.deepclean.installedapp.InstalledAppsActivity", }, { name: "应用信息", - fn: () => { - return startActivity({ - packageName: "com.android.settings", - className: ".applications.ManageApplications", - }); - }, - + packageName: "com.android.settings", + className: ".applications.ManageApplications", }, -]; +].map(action => { + return app.getAppName(action.packageName) + ? { + name: action.name, + fn: () => startActivity({ + packageName: action.packageName, + className: action.className, + }), + } + : null; +}).filter(Boolean); diff --git a/src/miui_cleaner_app/downApp.js b/src/miui_cleaner_app/downApp.js index b6b0418..c145fd3 100644 --- a/src/miui_cleaner_app/downApp.js +++ b/src/miui_cleaner_app/downApp.js @@ -53,6 +53,11 @@ const appList = [ 28: "https://www.123pan.com/s/OZe0Vv-qOKl3", }[device.sdkInt], }, + { + name: "应用包管理组件 - 不含“纯净模式”", + packageName: "com.miui.packageinstaller", + url: "https://zisu.lanzoum.com/iI7LGwn5xjc", + }, { name: "Holi 天气", packageName: "com.joe.holi", diff --git a/src/miui_cleaner_app/notification.js b/src/miui_cleaner_app/notification.js index 7644b92..84be487 100644 --- a/src/miui_cleaner_app/notification.js +++ b/src/miui_cleaner_app/notification.js @@ -1,4 +1,4 @@ -const requestPermission = require("./requestPermission"); +const requestSetting = require("./requestSetting"); const blur = require("./blur"); function notification () { @@ -13,7 +13,7 @@ function notification () { console.error(ex.message); return; } - requestPermission({ + requestSetting({ accessibility: true, }); blur(); diff --git a/src/miui_cleaner_app/offAppAd.js b/src/miui_cleaner_app/offAppAd.js index 098a5e2..4e174eb 100644 --- a/src/miui_cleaner_app/offAppAd.js +++ b/src/miui_cleaner_app/offAppAd.js @@ -1,9 +1,11 @@ -const multiChoice = require("./multiChoice"); const findClickableParent = require("./findClickableParent"); -const requestPermission = require("./requestPermission"); +const requestSetting = require("./requestSetting"); +const multiChoice = require("./multiChoice"); +const test = require("./test/offAppAdTest"); // const instApk = require("./instApk"); // const downApp = require("./downApp"); -const test = require("./test/offAppAdTest"); +const Settings = android.provider.Settings; + function delay (time) { sleep(time || 0x200); } @@ -27,25 +29,40 @@ function isFrameLayout (linear) { return /\.FrameLayout$/.test(linear.className()); } +function getDefaultValue (value, defaultValu) { + return value == null + ? defaultValu + : value + ; +} + function walkListView (options = {}) { const adCheckBoxList = []; const adLinearList = []; - let inNotify; + let inNotifyMgr; const listView = findByClassName(/\.(RecyclerView|ListView)$/).filter(view => { const packageName = view.packageName(); - inNotify = packageName === "com.android.settings"; - return inNotify || packageName === options.packageName; + return options.packageName === packageName || (inNotifyMgr = packageName === "com.android.settings"); }).findOne(); delay(); - const regSwitchOn = inNotify + const regSwitchOn = inNotifyMgr ? null - : options.regSwitchOn || /^(仅在(WLAN|Wi-?Fi)下.*?|.*?广告(拦截|过滤)|去.*?广告)$/i; - const regSwitchOff = inNotify + : getDefaultValue( + options.regSwitchOn, + /^(仅在(WLAN|Wi-?Fi)下.*?|.*?广告(拦截|过滤)|去.*?广告)$/i, + ); + const regSwitchOff = inNotifyMgr ? /^允许通知$/ - : options.regSwitchOff || /猜你喜欢|天气视频|桌面搜索|用户体验|在线(内容)?服务|个性化|消息|广告|热[榜门]|推[荐广]|宫格[栏位]|技巧|热点|新闻|[资快]讯|推送(服务|通知)|通知栏|扫描内存|福利活动|显示天气服务/; - const regSubPage = inNotify + : getDefaultValue( + options.regSwitchOff, + /猜你喜欢|天气视频|桌面搜索|用户体验|在线(内容)?服务|个性化|消息|广告|热[榜门]|推[荐广]|宫格[栏位]|技巧|热点|新闻|[资快]讯|推送(服务|通知)|通知栏|扫描内存|福利活动|显示天气服务/, + ); + const regSubPage = inNotifyMgr ? null - : options.regSubPage || /^(高级|其他|消息[与和]?推送|.*?广告(拦截|过滤)|去.*?广告|(.*?((消息)?通知|隐私|功能|个性化|信息流|用户体验|[主首]页|闹钟)(设置|管理|服务|计划|[防保]护)))$/; + : getDefaultValue( + options.regSubPage, + /^(高级|其他|消息[与和]?推送|.*?广告(拦截|过滤)|去.*?广告|(.*?((消息)?通知|隐私|功能|个性化|信息流|用户体验|[主首]页|闹钟)(设置|管理|服务|计划|[防保]护)))$/, + ); if (!options.handle) { options.handle = {}; }; @@ -146,7 +163,7 @@ function walkListView (options = {}) { result[adLinear.text] = subResult; }); - if (!inNotify && !options.disableScroll && listView.scrollable() && listView.scrollForward()) { + if (!inNotifyMgr && !options.disableScroll && listView.scrollable() && listView.scrollForward()) { // 判断页面是否需要下滚 console.log("页面滑动"); delay(); @@ -225,6 +242,13 @@ function startAct (packageName, activity) { return result || true; } +function startIntent (options) { + context.startActivity(new android.content.Intent(Settings[options.intent])); + waitForPackage(options.packageName); + toastLog(`正在启动“${options.name}”`); + delay(); +} + function clickButton (btnLabelList, text) { if (!Array.isArray(btnLabelList)) { btnLabelList = [btnLabelList]; @@ -408,8 +432,8 @@ function startTask (options) { threadSkipPopupPage = threads.start(skipPopupPage); } options = { ...options }; - if (options.start) { - options.start(); + if (options.intent) { + startIntent(options); } else if (options.activity) { startAct(options.packageName, options.activity); } else { @@ -423,6 +447,7 @@ function startTask (options) { test(options, result); } } + function switchBroHomePage (listView, options) { // 小米浏览器及国际版的特别控件————版式切换 Array.from(listView.children()).some(linear => { @@ -477,6 +502,23 @@ function noop () { // } +function getSysConfig (space, key) { + // https://developer.android.google.cn/reference/android/provider/Settings + return Settings[space].getInt(context.getContentResolver(), key); +} + +function getGlobalConfig (key) { + return getSysConfig("Global", key); +} + +function getSecureConfig (key) { + return getSysConfig("Secure", key); +} + +// function getSystemConfig (key) { +// return getSysConfig("Secure", key); +// } + const cleanerList = [ { name: "先清理后台应用(推荐)", @@ -485,9 +527,40 @@ const cleanerList = [ { // 小米帐号 packageName: "com.xiaomi.account", + // activity: ".settings.SystemAdActivity", activity: ".ui.AccountSettingsActivity", regSubPage: /^关于.*?[帐账]号|系统.*?广告$/, regSwitchOff: /^系统.*?广告$/, + test: () => Settings.Global.getString(context.getContentResolver(), "passport_ad_status") !== "OFF", + entry: noop, + }, + { + name: "系统安全", + packageName: "com.android.settings", + intent: "ACTION_SECURITY_SETTINGS", + regSubPage: /(广告|链接调用)/, + regSwitchOff: /诊断数据|广告推荐|链接调用|用户体验/, + test: () => [ + // 网页链接调用服务 + "http_invoke_app", + // 加入“用户体验改进计划” + "upload_log_pref", + // 自动发送诊断数据 + "upload_debug_log_pref", + + ].some(getSecureConfig), + entry: noop, + }, + { + // `广告服务` 位于 `安全` 的子页面 + name: "广告服务", + packageName: "com.android.settings", + activity: ".ad.AdServiceSettings", + regSwitchOff: /.*/, + test: () => getGlobalConfig( + // 个性化广告推荐 + "personalized_ad_enabled", + ), entry: noop, }, { @@ -640,7 +713,7 @@ const cleanerList = [ // // 打开知乎去广告插件-知了 // regSubPage: /^知了$/, // regSwitchOn: /^(启用知了|去.*?广告)$/, - // regSwitchOff: null, + // regSwitchOff: false, // done: function (result) { // if (!Object.keys(result.handle).length) { // startTask(this); @@ -665,6 +738,23 @@ const cleanerList = [ }); function offAppAd () { + const resolver = context.getContentResolver(); + try { + // https://developer.android.google.cn/reference/android/provider/Settings + // 系统安全 -> 广告服务 -> 个性化广告推荐:关闭 + Settings.Global.putInt(resolver, "personalized_ad_enabled", 0); + [ + // 网页链接调用服务 + "http_invoke_app", + // 加入“用户体验改进计划” + "upload_log_pref", + // 自动发送诊断数据 + "upload_debug_log_pref", + ].forEach(key => Settings.Secure.putInt(resolver, key, 0)); + } catch (ex) { + console.log("adb shell pm grant com.github.gucong3000.miui.cleaner android.permission.WRITE_SECURE_SETTINGS"); + } + const menuItemList = cleanerList.filter((appInfo) => { if (appInfo.packageName && !appInfo.appName && !appInfo.name) { appInfo.appName = app.getAppName(appInfo.packageName); @@ -672,10 +762,13 @@ function offAppAd () { return false; } } + if (appInfo.test) { + return appInfo.test(); + } return true; }); - requestPermission({ + requestSetting({ accessibility: true, drawOverlay: true, }); @@ -692,6 +785,9 @@ function offAppAd () { } tasks.forEach(task => { + if (task.test && !task.test()) { + return; + } task.fn ? task.fn() : startTask(task); }); console.hide(); diff --git a/src/miui_cleaner_app/recycle.js b/src/miui_cleaner_app/recycle.js index d72b646..9652027 100644 --- a/src/miui_cleaner_app/recycle.js +++ b/src/miui_cleaner_app/recycle.js @@ -1,7 +1,7 @@ +const findClickableParent = require("./findClickableParent"); +const requestSetting = require("./requestSetting"); const singleChoice = require("./singleChoice"); const instApk = require("./instApk"); -const requestPermission = require("./requestPermission"); -const findClickableParent = require("./findClickableParent"); const blur = require("./blur"); const marketPackageName = "com.xiaomi.market"; @@ -45,7 +45,7 @@ function getInstalledPackages () { // dataDir: appInfo.dataDir, apk: appInfo.sourceDir, // publicSourceDir: appInfo.publicSourceDir, - // deviceProtectedDataDir: appInfo.deviceProtectedDataDir + // deviceProtectedDataDir: appInfo.deviceProtectedDataDir, }; }).filter(Boolean); } @@ -54,7 +54,7 @@ function recycle () { const appInfo = singleChoice("请选择要恢复的应用", getInstalledPackages().concat({ name: "其他" })); if (appInfo) { console.log(appInfo); - requestPermission({ + requestSetting({ accessibility: true, }); if (appInfo.apk) { diff --git a/src/miui_cleaner_app/regtest.js b/src/miui_cleaner_app/regtest.js deleted file mode 100644 index 5e7618c..0000000 --- a/src/miui_cleaner_app/regtest.js +++ /dev/null @@ -1,110 +0,0 @@ -const text = ` -内容推广 -资源推荐 -热榜推荐 -允许通知 -新手帮助 -推送消息 -点赞消息 -评论消息 -个性化服务 -天气视频卡片 -天气服务推荐 -接收小米推送 -接收置顶消息 -使用个人信息进行推荐 -消息推送 -推荐内容 -推荐内容 -资源推荐 -猜你喜欢 -个性化服务 -个性化服务 -信息流推荐 -桌面搜索框 -开启生活早报 -接受消息通知 -允许Wap推送 -猜你喜欢 -系统工具广告 -//https://zhuanlan.zhihu.com/p/509571194 -1、日历 → ┇ → 设置 → 用户体验计划 → 内容推广,关闭; -2、文件管理 → ↓ ( 下载管理 ) → ┇ → 设置 → 信息流设置 → ,关闭; -3、文件管理 → ↓ ( 下载管理 ) → ┇ → 设置 → 信息流设置 → ,关闭; -4、应用商店 → 我的 → 设置 → 通知设置 → ,关闭; -5、应用商店 → 我的 → 设置 → 通知设置 → → ,关闭; -6、应用商店 → 我的 → 设置 → 通知设置 → ,关闭; -7、应用商店 → 我的 → 设置 → 通知设置 → ; -8、应用商店 → 我的 → 设置 → 隐私设置 → ,关闭; -9、天气 → ┇ → 设置 → 用户体验计划 → ,关闭; -10、天气 → ┇ → 设置 → 用户体验计划 → ,关闭; -11、小米视频 → 我的 → 设置 → 消息与推送 → ,关闭; -12、小米视频 → 我的 → 设置 → 消息与推送 → ,关闭; -13、主题壁纸 → 我的 → 设置 → 个性化推荐,关闭; -14、游戏中心 → 我的 → 设置 → 隐私设置 → ,关闭; -15、小米商城 → 我的 → 设置 → 消息推送 → ,关闭; -16、手机管家 → 安全中心 → 设置 → 垃圾清理 → ,关闭; -17、手机管家 → 安全中心 → 设置 → ,关闭; -18、设置 → 应用设置 → 应用管理 → ┇ → 设置 → ,关闭; -19、打开任一桌面文件夹 → 单击文件夹名称 → ,关闭。 -20、小爱同学→设置→关于小爱→关闭“ 加入用户体验计划”→隐私开关→关闭“​ -21、小米社区(可以直接卸载) →我的→设置→高级设置→关闭“详情推荐相似”&“个性化推荐”&“” -22、桌面下方搜索栏→右上角三个点→设置→消息通知管理→关闭“允许通知”→返回→搜索快捷方式→关闭“” -23、时钟→右上角→生活早报→关闭‘” -24、浏览器→菜单→设置→主页设置→简洁版→关闭“宫格栏推送”→返回→接收消息通知→关闭“” -25、短信→右上角设置→高级设置(倒数第二个) →关闭“” -26、桌面→打开任意文件夹→点击文件夹名称→关闭“” -27、桌面左滑打开负一屏→划到底部→设置→服务管理→选择关闭项目 -28、设置→小米账号→声明与条款→系统广告→→关闭 - - -热门活动 -资源推荐 -个性化广告推荐 -加入用户体验改进计划 -评论消息 -点赞消息 -个性化服务 -显示生活早报 -宫格位推送 -资源推荐 -资源推荐 -热榜推荐 -接收置顶消息 -接收置顶消息 -今日推荐 - -// 评论区 -MIUI13.0.12(2022-06-04): -1、设置 → 小米帐号 → 关于小米帐号 → 系统广告 → 系统工具广告,关闭; -2、设置 → 桌面 → 桌面搜索框,关闭; -3、设置 → 桌面 → 智能助理设置 → 实时动态 & 推荐卡片 & ,关闭; -4、设置 → 应用设置 → 应用管理 → ┇ → 设置 → 资源推荐,关闭; -5、设置 → 小爱同学 → 隐私管理 → 隐私设置 → & ,关闭; -6、打开任一桌面文件夹 → 单击文件夹名称 → 今日推荐,关闭; -7、桌面左滑打开负一屏 → 长按不想看的小部件,移除; -8、手机管家 → 设置 → 垃圾清理 → 推荐内容,关闭; -9、手机管家 → 设置 → 隐私设置 → 个性化推荐,关闭; -10、应用商店 → 我的 → 设置 → 通知设置 → 新手帮助 & 应用更新通知 & & ,关闭; -11、应用商店 → 我的 → 设置 → 隐私设置 → 个性化服务 → ,关闭; -12、时钟 → ┇ → 生活早报 → 开启生活早报,关闭; -13、时钟 → ┇ → 设置 → 更多闹钟设置 → ,关闭; -14、浏览器 → 我的 → 设置 → 简洁版;,关闭; - -可移除: -15、日历 → ┇ → 设置 → 用户体验计划 → 内容推广,关闭; -16、文件管理 → ↓ ( 下载管理 ) → ┇ → 设置 → 信息流设置 → & 热榜推荐,关闭; -17、主题壁纸 → 我的 → 设置 → 隐私设置 → 个性化推荐,关闭; -18、小米视频 → 我的 → 设置 → 消息与推送 → 接收小米推送 & 接收置顶消息,关闭; - -可卸载: -19、天气 → ┇ → 设置 → 用户体验计划 → 天气视频卡片 & 内容推广,关闭; -20、游戏中心 → 我的 → 设置 → 隐私设置 → 个性化服务,关闭; -21、小米商城 → 我的 → 设置 → 消息推送 → 消息推送,关闭; -22、小米社区 → 头像 → 设置 → 隐私管理 → 详情页相似推荐 & 个性化推,关闭; -`; - -const regSwitch = /通知|猜你喜欢|天气视频|桌面搜索|生活早报|用户体验|个性化|消息|广告|热[榜门]|推[荐广送]/gm; -const regSubPage = /(清理垃圾|简洁版|((通知|隐私|功能|个性化|信息流|用户体验|主页设置)(设置|管理|服务|计划)))/g; -console.log(text.match(regSwitch)); -// console.log(text.match(regSubPage)); diff --git a/src/miui_cleaner_app/requestPermission.js b/src/miui_cleaner_app/requestPermission.js deleted file mode 100644 index ab23834..0000000 --- a/src/miui_cleaner_app/requestPermission.js +++ /dev/null @@ -1,110 +0,0 @@ -// https://www.coder.work/article/1171167 - -const findClickableParent = require("./findClickableParent"); - -/** - * 请求 APP 的系统权限 - * @param {object} options 包名 - * @param {bool} options.accessibility 无障碍、可访问性 - * @param {bool} options.drawOverlay 悬浮窗、允许显示在其他应用的上层 - * @param {bool} options.captureScreen 截图 - */ -function requestPermission (options = {}) { - options = { - accessibility: true, - ...options, - }; - - threads.start(() => { - if (options.accessibility) { - auto.waitFor(); - } - if (options.drawOverlay) { - setDrawOverlay(); - } - if (options.captureScreen) { - setCaptureScreen(); - } - }); -} - -function clickCheckBox (expect, packageName) { - let checkBox = selector().packageName(packageName).className("CheckBox").findOne(); - const value = checkBox.checked(); - if (value === expect) { - return expect; - } else { - checkBox = findClickableParent(checkBox); - if (checkBox) { - checkBox.click(); - return expect; - } - } - return value; -} - -/** - * 请求或自动化获得截图权限 - * @returns {bool} - */ -function setDrawOverlay () { - let value = floaty.checkPermission(); - if (!value) { - floaty.requestPermission(); - try { - value = clickCheckBox(true, "com.android.settings"); - } catch (ex) { - toastLog("请打开“悬浮窗”权限,以便自动化操作"); - } - if (value) { - back(); - } - } - return value; -} - -/** - * 查询目前是否有截图权限 - * @returns {bool} - */ -function getCaptureScreen () { - try { - images.captureScreen(); - } catch (ex) { - return false; - } - return true; -} - -/** - * 请求或自动化获得截图权限 - * @returns {bool} - */ -function setCaptureScreen () { - let value = getCaptureScreen(); - - if (!value) { - // 先打开悬浮窗权限,因为MIUI可能有Bug,截图权限授权弹窗可能有时候不显示,先给悬浮窗权限就没问题了。 - setDrawOverlay(); - - // 尝试使用“无障碍”权限获得的自动化操作能力自动点击,拿到截图权限 - const thread = threads.start(function () { - try { - const packageName = "com.android.systemui"; - clickCheckBox(true, packageName); - findClickableParent(selector().packageName(packageName).text("立即开始").findOne()).click(); - } catch (ex) { - // - } - }); - value = images.requestScreenCapture(); - thread.interrupt(); - - if (!value) { - toastLog("请打开“截图”权限,以便能能识别开关"); - } - } - return value; -} - -module.exports = requestPermission; diff --git a/src/miui_cleaner_app/requestSetting.js b/src/miui_cleaner_app/requestSetting.js new file mode 100644 index 0000000..cd37724 --- /dev/null +++ b/src/miui_cleaner_app/requestSetting.js @@ -0,0 +1,181 @@ +// https://www.coder.work/article/1171167 + +const findClickableParent = require("./findClickableParent"); + +/** + * 请求 APP 的系统权限 + * @param {object} options 包名 + * @param {bool} options.accessibility 无障碍、可访问性 + * @param {bool} options.drawOverlay 悬浮窗、允许显示在其他应用的上层 + * @param {bool} options.captureScreen 截图 + */ +function requestPermission (options = {}) { + if (options.accessibility) { + enableAccessibility(); + } + if (options.drawOverlay) { + enableDrawOverlay(); + } + if (options.captureScreen) { + enableCaptureScreen(); + } + if (options.development) { + enableDevelopment(); + } + if (options.adb) { + enableADB(); + } +} + +function clickCheckBox (expect, packageName) { + let checkBox = selector().packageName(packageName).checkable(true).findOne(); + const value = checkBox.checked(); + if (value === expect) { + return expect; + } else { + checkBox = findClickableParent(checkBox); + if (checkBox) { + checkBox.click(); + return expect; + } + } + return value; +} + +function enableAccessibility () { + auto.waitFor(); +} + +/** + * 开启悬浮窗权限 + * @returns {bool} + */ +function enableDrawOverlay () { + let value = floaty.checkPermission(); + if (!value) { + enableAccessibility(); + floaty.requestPermission(); + try { + value = clickCheckBox(true, "com.android.settings"); + } catch (ex) { + toastLog("请打开“悬浮窗”权限,以便自动化操作"); + } + if (value) { + back(); + } + } + return value; +} + +/** + * 获取Android配置信息 + * @param {String} key 配置项名称 + * @returns {Int} + */ +function getGlobalSetting (key) { + // https://developer.android.google.cn/reference/android/provider/Settings.Global + return android.provider.Settings.Global.getInt(context.getContentResolver(), key); +} + +function findBtnInView (intent, text) { + enableAccessibility(); + context.startActivity(new android.content.Intent(android.provider.Settings[intent])); + sleep(0x200); + const listView = selector().packageName("com.android.settings").scrollable(true).findOne(); + sleep(0x200); + let btn; + do { + btn = selector().packageName("com.android.settings").text(text).findOnce(); + if (btn) { + break; + } else { + sleep(0x200); + } + } while (listView.scrollForward()); + return findClickableParent(btn); +} + +/** + * 打开开发者选项 + * @returns {bool} + */ +function enableDevelopment () { + let value = getGlobalSetting("development_settings_enabled"); + if (!value) { + const btnMIUI = findBtnInView("ACTION_DEVICE_INFO_SETTINGS", "MIUI 版本"); + if (btnMIUI) { + for (let i = 0; i < 9; i++) { + btnMIUI.click(); + } + value = true; + } + } + return value; +} + +/** + * 打开`USB调试`既ADB权限 + * @returns {bool} + */ +function enableADB () { + let value = getGlobalSetting("adb_enabled"); + if (!value) { + enableDevelopment(); + const btnUSB = findBtnInView("ACTION_APPLICATION_DEVELOPMENT_SETTINGS", "USB 调试"); + if (btnUSB) { + btnUSB.click(); + let btnAllow; + do { + const checkBox = selector().id("check_box").packageName("com.miui.securitycenter").findOnce(); + if (checkBox && !checkBox.checked()) { + findClickableParent(checkBox).click(); + } + btnAllow = selector().id("intercept_warn_allow").packageName("com.miui.securitycenter").findOne(0x200); + if (btnAllow) { + findClickableParent(btnAllow).click(); + } + } while (btnAllow); + back(); + value = true; + } + } + return value; +} + +/** + * 开启截图权限 + * @returns {bool} + */ +function enableCaptureScreen () { + let value = true; + try { + images.captureScreen(); + } catch (ex) { + value = false; + } + + if (!value) { + // 尝试使用“无障碍”权限获得的自动化操作能力自动点击,拿到截图权限 + enableAccessibility(); + // 先打开悬浮窗权限,因为MIUI可能有Bug,截图权限授权弹窗可能有时候不显示,先给悬浮窗权限就没问题了。 + enableDrawOverlay(); + const thread = threads.start(function () { + try { + const packageName = "com.android.systemui"; + clickCheckBox(true, packageName); + findClickableParent(selector().packageName(packageName).text("立即开始").findOne()).click(); + } catch (ex) { + // + } + }); + value = images.requestScreenCapture(); + thread.interrupt(); + + if (!value) { + toastLog("请打开“截图”权限,以便能能识别开关"); + } + } + return value; +} + +module.exports = requestPermission; diff --git a/src/miui_cleaner_app/startActivity.js b/src/miui_cleaner_app/startActivity.js index d7cd4f4..0088e47 100644 --- a/src/miui_cleaner_app/startActivity.js +++ b/src/miui_cleaner_app/startActivity.js @@ -1,4 +1,4 @@ -const requestPermission = require("./requestPermission"); +const requestSetting = require("./requestSetting"); const blur = require("./blur"); function startActivity (options) { @@ -9,7 +9,7 @@ function startActivity (options) { console.error(ex.message); return; } - requestPermission({ + requestSetting({ accessibility: true, }); blur(); diff --git a/src/miui_cleaner_app/sysAppRm.js b/src/miui_cleaner_app/sysAppRm.js index 8a5625f..6adca2f 100644 --- a/src/miui_cleaner_app/sysAppRm.js +++ b/src/miui_cleaner_app/sysAppRm.js @@ -1,6 +1,6 @@ -const multiChoice = require("./multiChoice"); -const blur = require("./blur"); const findClickableParent = require("./findClickableParent"); +const requestSetting = require("./requestSetting"); +const multiChoice = require("./multiChoice"); function clickButton (button, text) { button = findClickableParent(button); @@ -164,6 +164,22 @@ function getAppList () { appInfo.appName = app.getAppName(appInfo.packageName); return appInfo.appName; }); + const fileName = "MiuiPackageInstaller.apk"; + const srcPath = "res/" + fileName; + const copyPath = "/sdcard/Download/" + fileName; + const installPath = "/data/local/tmp/" + fileName; + files.copy(srcPath, copyPath); + appList.push({ + packageName: "com.miui.packageinstaller", + name: "纯净模式", + cmd: [ + `mv ${copyPath} ${installPath}`, + "pm install -d -g " + installPath, + "rm -rf " + installPath, + ].join("\n"), + }); + console.log(files.isFile("res/MiuiPackageInstaller.apk")); + console.log(files.exists("res/MiuiPackageInstaller.apk")); return appList; } @@ -199,25 +215,28 @@ module.exports = () => { } const helper = threads.start(installerHelper); tasks.forEach(appInfo => { - app.uninstall(appInfo.packageName); + appInfo.cmd || app.uninstall(appInfo.packageName); }); - blur(); + + do { + sleep(0x400); + } while (selector().filter(sth => /installer/i.test(sth.packageName())).findOnce()); + helper.interrupt(); tasks = tasks.filter( appInfo => app.getAppName(appInfo.packageName), ).map(appInfo => { - return "pm uninstall --user 0 " + appInfo.packageName; + return appInfo.cmd || "pm uninstall --user 0 " + appInfo.packageName; }); if (!tasks.length) { return; } - - const cmdOffAd = "settings put global passport_ad_status OFF"; + const cmdGrant = `pm grant ${context.getPackageName()} android.permission.WRITE_SECURE_SETTINGS`; let root; try { - shell(cmdOffAd, true); + shell(cmdGrant, true); } catch (ex) { root = false; } @@ -230,7 +249,7 @@ module.exports = () => { tasks.push("rm -rf " + shFilePath); const script = [ "#!/bin/sh", - cmdOffAd, + cmdGrant, ].concat(tasks).join("\n") + "\n"; files.write(shFilePath, script); @@ -238,12 +257,15 @@ module.exports = () => { const cmd = "adb shell sh " + shFilePath; console.log("正以等候电脑端自动执行:\n" + cmd); toast("正以等候电脑端自动执行"); - const startTime = Date.now(); + const timeout = Date.now() + 0x800 + tasks.length * 0x200; let fileExist; + requestSetting({ + adb: true, + }); do { sleep(0x200); fileExist = files.exists(shFilePath); - } while (fileExist && Date.now() - startTime < 0x1000); + } while (fileExist && Date.now() < timeout); if (fileExist) { dialogs.rawInput("等候电脑端自动执行超时,请在电脑手动执行命令:", cmd); } else { diff --git a/src/miui_cleaner_app/test/offAppAdTest.js b/src/miui_cleaner_app/test/offAppAdTest.js index 3670f3b..ee9bb51 100644 --- a/src/miui_cleaner_app/test/offAppAdTest.js +++ b/src/miui_cleaner_app/test/offAppAdTest.js @@ -9,10 +9,22 @@ const testData = { 关于小米帐号: { 系统广告: { 系统工具广告: false, - 查看涉及应用列表: null, }, }, }, + 广告服务: { + 个性化广告推荐: false, + }, + 系统安全: { + "加入“用户体验改进计划”": false, + "自动发送诊断数据": false, + "广告服务": { + 个性化广告推荐: false, + }, + "网页链接调用服务": { + 网页链接调用服务: false, + }, + }, 手机管家: { 在通知栏显示: false, 在线服务: false, @@ -195,9 +207,9 @@ module.exports = (options, result) => { const testCaseName = options.name || options.appName || app.getAppName(options.packageName); const data = testData[testCaseName]; + // console.log(JSON.stringify(result.handle, 0, "\t")); try { if (!data) { - // console.log(JSON.stringify(result, 0, "\t")); const error = new Error(`广告自动关闭模块功能异常: “${testCaseName}”中,未编写测试用例`); throw error; } diff --git a/src/miui_cleaner_cmd/main.cmd b/src/miui_cleaner_cmd/main.cmd index 054824d..d4604bf 100644 --- a/src/miui_cleaner_cmd/main.cmd +++ b/src/miui_cleaner_cmd/main.cmd @@ -1,6 +1,4 @@ @echo off -@REM CHCP 65001>nul 2>nul - title MiuiCleaner - MIUI广告清理工具 :start @@ -31,7 +29,7 @@ call:pkg_exist "com.github.gucong3000.miui.cleaner" || ( echo 正在手机上安装 MiuiCleaner.apk, 请打开“设置 → 更多设置 → 开发者选项 → USB安装” call:apk_install ) else ( - echo 未在手机上找到“MiuiCleaner”,请将““MiuiCleaner.apk”拷贝至“%CD%”文件夹,或直接安装在手机后,按任意键重试 + echo 未在手机上找到“MiuiCleaner”,请将“MiuiCleaner.apk”拷贝至"%CD%"文件夹,或直接安装在手机后,按任意键重试 pause>nul 2>nul goto:start ) @@ -44,6 +42,7 @@ adb shell settings put secure install_non_market_apps 1 @REM adb shell settings get secure enabled_accessibility_services adb shell pm grant com.github.gucong3000.miui.cleaner android.permission.WRITE_SETTINGS>nul 2>nul +adb shell pm grant com.github.gucong3000.miui.cleaner android.permission.WRITE_SECURE_SETTINGS>nul 2>nul adb shell pm grant com.github.gucong3000.miui.cleaner android.permission.SYSTEM_ALERT_WINDOW>nul 2>nul adb shell am start -n com.github.gucong3000.miui.cleaner/com.stardust.auojs.inrt.SplashActivity>nul 2>nul