一个人写了大半年 Android App,聊聊过程中的一些取舍 - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
请不要在回答技术问题时复制粘贴 AI 生成的内容
putilaoha

一个人写了大半年 Android App,聊聊过程中的一些取舍

  •  1
     
  •   putilaoha 3 月 25 日 3214 次点击

    App 是 Meows ,Android 上的 Linux 服务器监控工具,纯原生 Jetpack Compose 开发,之前发过几次。这次不介绍功能了,聊聊开发过程中一些纠结过的点。

    要不要装 agent

    一开始也考虑过走 agent 方案,服务端装个守护进程推数据,能做的事情多很多。但想了想,我自己作为用户其实最烦在服务器上多装东西,尤其是小鸡,本来资源就不多。

    最后选了纯 SSH ,好处是零侵入,坏处是能拿到的数据有限,得在客户端做更多解析。这个取舍到现在觉得是对的填个地址就能看到所有指标,不用折腾。

    总览控制台

    CPU 、内存、磁盘、上下行流量、TCP 连接数、在线时长,实时刷新。9 种指标都有历史曲线,可以切 1 分钟 / 2 分钟 / 5 分钟跨度。

    流量图表

    终端要不要自己写

    调研了一下 Android 上能用的终端库,要么太老,要么和 Compose 不兼容。最后决定自己写 ANSI 解析引擎,手搓状态机。

    写完才发现这东西是个坑光是 CJK 全角字符的宽度处理就搞了好几天,还有各种转义序列的边界情况。不过好处是完全可控,后面加语义着色就很自然:终端自动识别输出内容类型上色,文件权限逐字符着色( r 绿 w 橙 x 红)、路径按类型区分(/etc 配置色、/var/log 日志色)、IP 地址、百分比阈值着色(≥90% 红、≥70% 黄),比纯白字看着舒服不少。

    终端语义着色

    nano 、vim 、htop 都能正常跑,底部有快捷键栏,支持跳板机,内置了 4 款等宽字体可选。

    nano 编辑器

    关于定价和安全

    $4.99 一次买断,没有订阅,没有内购,没有广告,后续更新免费。去年 10 月底上架,到现在版本号刷到 1.0.144 了。

    不想做免费 + 广告,一是体验差,二是不想接第三方 SDK 。App 只申请了通知权限,不收集不共享任何数据。所有密码和私钥走 AES-GCM + Android Keystore 硬件级加密,不是明文落盘。

    设置页面

    其他功能

    • 告警:CPU 、内存、磁盘阈值 + 掉线通知,多指标超标合并推送,有防抖
    • 离线 IP 库 + 骨干网识别( CN2 、9929 、CMI 这些)
    • 8 项流媒体 / AI 解锁检测,直接显示在卡片上
    • SSH 登录失败次数统计,一眼看出有没有被暴力破解
    • Google Drive 加密备份,换机一键恢复

    告警设置

    卡片徽章配置

    下载

    Google Play 搜 Meows

    https://play.google.com/store/apps/details?id=com.meows.android

    上架地区: 日本、美国、新加坡、韩国、香港、台湾、英国、加拿大、澳门、马来西亚、冰岛。

    要求: Android 14+,Google Play 商店 → 设置 → 关于 → 「设备已通过认证」( Google Play 策略,非 App 限制。解锁 bootloader 的设备可能显示未认证,可先在网页端入库)。支持简中 / 繁中 / 英 / 日 / 韩。

    有问题或建议可以直接回帖,我都会看。

    33 条回复    2026-03-27 12:41:15 +08:00
    lambdavip2022
        1
    lambdavip2022  
       3 月 25 日
    这个需要在服务器安装对应的 server 组件吗?还是只需要手机安装 APK 就可以用了。
    putilaoha
        2
    putilaoha  
    OP
       3 月 25 日
    @lambdavip2022 不需要,服务器端零安装。手机装好 App ,填上服务器 IP 和 SSH 账号就能用,针对这个问题,文章第一节说过了
    Cabana
        3
    Cabana  
       3 月 25 日 via iPhone
    在用 serverbox ,它的终端是真难用
    bkmi
        4
    bkmi  
       3 月 25 日 via Android
    不让下载,“您的设备与此版本不兼容”
    Samsung S25 Ultra Android 16
    mosanHZ
        5
    mosanHZ  
       3 月 25 日
    告警是实时的?岂不是要常驻手机后台?
    putilaoha
        6
    putilaoha  
    OP
       3 月 25 日
    @bkmi 请先确保 Google Play Store 应用的认证显示为“设备已通过认证”
    bkmi
        7
    bkmi  
       3 月 25 日 via Android
    @putilaoha 那不行了,手机 root 了
    putilaoha
        8
    putilaoha  
    OP
       3 月 25 日
    @bkmi 文章里有写:( Google Play 策略,非 App 限制。解锁 bootloader 的设备可能显示未认证,可先在网页端入库)
    bjzhou1990
        9
    bjzhou1990  
       3 月 25 日
    牛逼,但是 M3 真的丑
    putilaoha
        10
    putilaoha  
    OP
       3 月 25 日
    @bjzhou1990 M3 设计我觉得还行,换个好看的壁纸可能会好点,毕竟动态取色跟壁纸走的
    vt2rexm
        11
    vt2rexm  
       3 月 25 日
    这算不算是一种探针的 app 化?
    putilaoha
        12
    putilaoha  
    OP
       3 月 25 日
    @vt2rexm 差不多吧,一开始是给自己用的。传统探针要在服务器上装 agent ,配环境配权限,数据还得过第三方。我不太习惯这套,就做了这个,数据加密落盘到本地,服务器上什么都不用装,甚至 app 也只需要一个通知权限,非常轻
    leiuu
        13
    leiuu  
       3 月 25 日
    不错 界面比很多监控软件现代化多了
    有借助 ai 编程吗 效果怎样
    另外有个风险是本地需要保存很多服务器的私钥吧
    putilaoha
        14
    putilaoha  
    OP
       3 月 25 日
    @leiuu 你说到点子上了,这也是我开发时遵循的一个理念,就是安全性。所有凭证走 AES-GCM + Android Keystore 加密存储,不是明文落盘。密钥由系统底层托管,不存在 App 的存储空间里,即使数据库被拖走也解不出来。
    magicls
        15
    magicls  
       3 月 25 日
    很不错啊,支持一下。iOS 上有个 ServerCat ,现在 Android 终于有了。
    putilaoha
        16
    putilaoha  
    OP
       3 月 25 日
    @magicls 好家伙,看名字怎么也是猫系软件
    magicls
        17
    magicls  
       3 月 25 日
    @putilaoha #16 老实说,我刚才很想试试,但是搜过去一看 39.99 HKD,ummmm……。

    其实愿意为好东西付费的人不少,但大部分人还是喜欢先看一眼。我看站内你也推广了不少,好 app 不应该被埋没,只是我温和建议老哥下一版改成免费试用 + 收费继续用的模式吧?或者免费的只能添加 1 台 server ,付费或订阅解锁更多这样…
    putilaoha
        18
    putilaoha  
    OP
       3 月 25 日
    @magicls 理解第一眼的犹豫。不过算下来其实就一杯咖啡的价格(节假日有打折活动),买断永久用,没有订阅没有内购,后续版本更新也一直免费
    qwell
        19
    qwell  
       3 月 25 日
    可以,老哥很强
    putilaoha
        20
    putilaoha  
    OP
       3 月 25 日
    @qwell 因为主要是自用,所以没啥压力,可以静下来做一个东西
    guanzhangzhang
        21
    guanzhangzhang  
       3 月 25 日
    as 才有 compose 预览,ai 写的还是纯手写的,ai 写的话 compose 预览啥的咋解决
    putilaoha
        22
    putilaoha  
    OP
       3 月 25 日
    @guanzhangzhang 手搓,ANSI 解析引擎也是,另外 Compose 预览?我都是真机调试啊,没必要啊
    bingoso
        23
    bingoso  
       3 月 26 日 via iPhone
    app 不常驻后台也能实时告警吗?
    smilingsun
        24
    smilingsun  
       3 月 26 日 via Android
    支持 ssh via http proxy 吗
    bkmi
        25
    bkmi  
       3 月 26 日 via Android
    下载了,但是无论如何也连不上内网服务器
    putilaoha
        26
    putilaoha  
    OP
       3 月 26 日
    @bingoso 内网服务器的话,可以配置 SSH 跳板机
    bkmi
        27
    bkmi  
       3 月 26 日
    ed25519 连不上,rsa 连上了,
    另外到终端界面选了服务器一片空白,我也不知道要点击右上角连接,为何不直接从首页进终端呢
    终端底部快捷栏的方向键,左右拖到就触发点击了
    putilaoha
        28
    putilaoha  
    OP
       3 月 26 日
    @bkmi RSA 、ED25519 、ECDSA 都支持,连不上的话可以检查一下:私钥粘贴的时候有没有多余的空行或空格?如果私钥有 passphrase 的话需要一并填上
    putilaoha
        29
    putilaoha  
    OP
       3 月 26 日
    @bkmi 关于“终端连接”,这个是有意的设计。SSH 连接和断开是一对显式操作,选服务器只是选择,连接需要确认。这样切换服务器的时候不会触发不必要的断开重连,断开后也能明确地手动重连
    putilaoha
        30
    putilaoha  
    OP
       3 月 26 日
    @bkmi 可以发下你的邮箱吗?我拉你入群
    bingoso
        31
    bingoso  
       3 月 27 日 via iPhone
    @putilaoha 仔细看了下,终于理解了,你这是把密钥存到你的云服务器了,告警其实是云端对服务器的检查。
    putilaoha
        32
    putilaoha  
    OP
       3 月 27 日 via iPhone
    @bingoso 你这不如不理解,密钥只存在你的手机上,用 Keystore 加密,不会上传到任何服务器
    bingoso
        33
    bingoso  
       3 月 27 日
    @putilaoha 哈哈 抱歉哈,不太了解安卓实时告警怎么回事,一直以为要常驻后台。理解偏差了,抱歉。
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     1046 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 62ms UTC 18:37 PVG 02:37 LAX 11:37 JFK 14:37
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86