让你的UFI-TOOls彻底属于你:老款中兴5G随身WIFI第三方web绿化教程
引言
这是一个第三方web项目,适用于中兴f50、u30、v50等设备,推广很多,本教程旨在让你获得此工具的完整控制能力,不再为频繁的更新弹窗和骚扰信息所困扰,享受属于自己的宁静
目录
- 绿化目标
- 环境准备(Android Studio + Node)
- 拉源码
- 关掉默认上报(最核心)
- 关掉远程消息/外链资源(让前端离线化)
- 移除 customHead 脚本执行入口(堵住“可下发前端逻辑”的口子)
- 更新链路自控(禁用 force、固定资源服务器/直接禁用在线更新)
- 去掉强制条款弹窗(可选)
- 重新打包前端资源到 APK
- 编译 APK
- 验证:我真的自由了吗?
1. 绿化目标(你最终要达成什么)
对“绿化/自控版”的定义很简单:任何“会联网、会更新、会执行外部内容、会强制弹窗”的能力,都变成“你可选择、可关闭、可审计”。
本文最终效果(建议抓包验证):
- 不再每 5 小时向
api.kanokano.cn上报uuid / 机型 / 版本 / root 状态 - 不再从远端拉“系统消息/公告”
- customHead 不再执行
<script>(外链、内联都不执行) - 更新不再因为文件名带
force就“强制不是最新”(你可以选择干掉/弱化) - “用户协议”弹窗不再作为使用门槛(可选)
2. 环境准备(Android Studio + Node)
2.1 你需要安装
- Android Studio(或命令行 Gradle)
- Node.js(用于把
app/frontEnd/public打包进app/src/main/assets) - Git(可选,但强烈建议)
2.2 关键目录说明(别改错地方)
UFI-Tools 的 Web 前端不是“运行时在线拉的”,而是 build 后塞进 APK 的 assets:
- 源码前端:
app/frontEnd/public/ - build 输出(APK 里用的):
app/src/main/assets/ - build 脚本:
app/frontEnd/build.js
所以:你改了 public 里的 JS/HTML,必须 npm run build 才会进 APK。
3. 拉源码
(如果你只是本地临时改改,也可以不推自己的仓库)
git clone https://github.com/kanoqwq/UFI-TOOLS.git cd UFI-TOOLS 删除.git文件夹 后续如需自己维护,可以重新git init 然后推到自己的远程仓库
4. 关掉不必要的信息上报
你也不喜欢你的设备使用情况被视奸吧
4.1 先确认:上报在什么地方?
上报实现在:
app/src/main/java/com/minikano/f50_sms/utils/KanoReport.kt
你会看到:
- 目标:
https://api.***.cn/ufi_tools_report/report - header:
token: **** - JSON:
uuid / device_name / app_ver / firmware_ver / is_root
触发点在:
app/src/main/java/com/minikano/f50_sms/ADBService.kt
它每 5 小时执行一次:
handler.postDelayed(this, TimeUnit.HOURS.toMillis(5))并且 ADBService 会被开机自启启动(所以会被认为“没打开同意也在跑”):
app/src/main/java/com/minikano/f50_sms/BootReceiver.kt
context.startForegroundService(Intent(context, ADBService::class.java))4.2 推荐改法:只断触发点(改动小、不容易编译炸)
文件:app/src/main/java/com/minikano/f50_sms/ADBService.kt
找到:
executor.execute(runnableRPT)改成(注释掉):
// executor.execute(runnableRPT)这样做的好处:
KanoReport.kt你可以暂时不动- 上报不会再被周期性触发
- 不影响其它模块编译
4.3 更彻底(进阶):保留 runnableRPT,但不再外连
如果你想保留“周期任务框架”但不想外连,改成只注释上报调用即可:
// reportToServer()5. 关掉远程消息推送
用于处理"放在错误的地方的开发者消息",比如小作文指责某些产品或者是无端弹出的收款码,尽管这听起来很荒谬,但的确发生过,所以我们选择眼不见心不烦的修改方法
5.1 关闭“系统消息/公告拉取”
文件:app/frontEnd/public/script/main.js
里面有一段“获取消息”的逻辑,关键点是硬编码了远端:
const api ='https://api.kanokano.cn/ufi_tools_report'// fetch(`${KANO_baseURL}/proxy/--${api}/get_message/${uuid}`)最简单做法:直接禁用 initMessage() 调用。
做法:
- 搜索
initMessage() - 把调用注释掉:
// initMessage()这一步建议直接做
6. 移除 customHead 脚本执行入口(很关键)
diy绿化版本的另一个重点就是把“可执行外部脚本”的入口堵住:你可以允许 CSS,但不要让 <script> 自动跑。
6.1 先确认:customHead 到底做了什么?
文件:app/frontEnd/public/script/main.js(开头附近有 //customHead)
它会把后端返回的 HTML 解析后塞进 <head>,并且会执行脚本:
doc.querySelectorAll('script').forEach(scriptEl=>{const newScript = document.createElement('script');if(scriptEl.src) newScript.src = scriptEl.src;// 外链脚本else newScript.textContent = scriptEl.textContent;// 内联脚本 document.head.appendChild(newScript);})6.2 绿化推荐改法 A:直接禁用 customHead
文件:app/frontEnd/public/script/main.js
把 customHead 整段 IIFE 注释掉即可(它本来就是一个独立块)。
6.3 绿化推荐改法 B:保留 style/link/meta,但丢弃 script
如果你确实想保留“自定义样式”,那就只保留:
doc.querySelectorAll('style, link, meta').forEach(...)script 部分改成“直接忽略”:
doc.querySelectorAll('script').forEach(()=>{// do nothing})不要指望“正则过滤危险关键字”来保留 script:你很难过滤干净,实际上想绕过很容易,后风险可想而知。
6.4 后端建议一起收口(避免未来又被接回来)
customHead 的后端接口在:
文件:app/src/main/java/com/minikano/f50_sms/modules/plugins/pluginsModule.kt
POST /api/set_custom_head:把 text 存到 SharedPreferencesGET /api/get_custom_head:读出来给前端
如果你选择彻底删除 customHead 功能,建议把这两个路由也删掉。
(不想删也行——但删掉更“干净”,以后不会被 UI/插件又用起来。)
7. 更新链路自控(禁用 force + 自建资源服务器/禁用在线更新)
我爱用哪个版本,你管得着吗?
7.1 禁用“force”对更新判断的影响
文件:app/frontEnd/public/script/main.js
你会看到类似逻辑:
if(name.includes('force')){ isLatest =false;}如果你不希望文件名影响“是否必须更新”,直接注释掉这一段即可。
7.2 资源服务器(插件/OTA)由你决定
后端有“资源服务器”概念,默认是:
文件:app/src/main/java/com/minikano/f50_sms/configs/AppMeta.kt
var GLOBAL_SERVER_URL ="https://pan.****.cn"并且提供 API 可在运行时修改:
文件:app/src/main/java/com/minikano/f50_sms/modules/config/configModule.kt
GET /api/get_res_serverPOST /api/set_res_server(body 里传res_server)
想完全自控有两条路:
- 你自建一个兼容的资源服务器(需要能提供
/api/fs/list这类接口,项目用的是 alist 风格) - 你直接禁用插件商店/在线 OTA(不依赖任何外部)
如果你只是想“不要默认连外网”,最简单是:把 res_server 改成你内网的服务或一个不可达地址,然后只用你自己手动安装的 APK。
8. 去掉强制条款弹窗
很多人都很反感“必须同意/必须输入确认文字”这种流氓条款,作为极客,我们完全可以把它删掉。
8.1 它是怎么判断“是否已同意”的?
后端把同意状态放在 SharedPreferences:
POST /api/accept_terms:把isReadUseTerms=true写入GET /api/version_info:返回accept_terms
前端通过 getTermsAcceptance() 去读 version_info,不通过就弹窗:
文件:app/frontEnd/public/script/requests.js
constgetTermsAcceptance=async()=>{const res =await(awaitfetchWithTimeout(`${KANO_baseURL}/version_info`)).json()ACCEPT_TERMS= res.accept_terms && res.accept_terms.toString()=='true'returnACCEPT_TERMS}8.2 绿化做法 A:前端不再弹(最简单)
文件:app/frontEnd/public/script/main.js
搜索 initTerms(),把它的调用注释掉:
// initTerms()(这样不会再弹窗拦路。)
8.3 绿化做法 B:后端默认视为已同意(更“彻底”)
如果你想让 version_info 永远返回 accept_terms=true,可以在初始化时把默认值改成 true:
文件:app/src/main/java/com/minikano/f50_sms/configs/AppMeta.kt
把:
isReadUseTerms = prefs.getString("isReadUseTerms","false").toBoolean()改成:
isReadUseTerms = prefs.getString("isReadUseTerms","true").toBoolean()9. 重新打包前端资源到 APK(很关键)
前面我们改的是:
app/frontEnd/public/script/main.jsapp/frontEnd/public/script/requests.js
这些改动 不会自动进 APK,必须跑前端 build:
cd app/frontEnd npminstall# 生产:会混淆 main.js/requests.js 并复制到 app/src/main/assets/npm run build # 如果你想调试(不混淆,方便看代码)npm run debug 成功后你会看到:
app/src/main/assets/里对应的文件被更新
10. 编译 APK
10.1 Android Studio 方式
打开项目根目录 UFI-TOOLS/:
- Gradle Sync
- Build -> Build APK(s)
10.2 命令行方式
在项目根目录执行:
./gradlew assembleDebug 生成的 APK 通常在类似路径(按 Gradle 配置为准):
app/build/outputs/apk/debug/ 11. 验证:我的ufi-tools实现自托管了吗?
建议你做两个验证:
11.1 抓包验证(推荐)
把设备连上网,打开/运行你编译的版本,观察:
- 是否还有
api.???cn的请求 - 是否还有周期性 POST(等一会儿/看日志/看计划任务)
11.2 日志验证(更直观)
KanoReport.kt、ADBService.kt 里有 log tag,你可以:
- 看 logcat
- 或者临时在关键分支加日志确认“触发点已断”
最后:
当一个工具同时具备 稳定标识上报、可下发前端内容并执行、更新链路可控 这些能力时——
哪怕它“当前看起来没出事”“我们相信开发者”,你也在被动承担一笔信任成本
绿化版的意义,就是把这笔成本降到最低:外连由你决定,逻辑由你审计,更新由你掌握,功能由你开发
开源的魅力就在于每个人都可以对项目进行审查、贡献,按照自己的喜好删删改改
欢迎star或者fork原项目,按照你的想法diy更好用的随身wifi管理工具