一只吃白饭的鲸鱼娘,挂在你的手机桌面上
不联网 · 不上传 · 不要账号
一个 Android 桌面宠物。她以一个极小的悬浮窗浮在屏幕上:
- 在你刷抖音、看视频的时候,嫌她挡视野就拖到屏幕侧边 —— 她会扒在边上,只露一个脑袋看着你
- 点她一下换一个表情,顺便吱一声(小黄鸭音效,可关)
- 长按弹出「设置 / 关闭」
所有东西都在你手机本地,没有任何网络请求。
想要两个角色? 社区做了一个双人互动版 —— 在原版之上加了第二个角色「GPT 小龙女」、双人随机互动和预设剧情,同样完全离线。 本仓库是原版,保持「一个人安静待着」。
| 负责 | |
|---|---|
| @LIN428924379 | 原作者 —— 角色设定、美术、交互设计、Android 版 |
| @duhaoze2007 | Windows 版、macOS 版与官网 —— 用原生 C++ / Swift 重写,并额外做了悬停气泡、自动换表情、菜单栏图标等功能 |
| @3108944309zpc-ctrl | 双人互动版(衍生仓库)—— 加了第二个角色「GPT 小龙女」、双人随机互动与预设剧情、气泡和特效;也修好了原版小米上点她没声音的 bug |
「白饭鱼」现在是一个项目、多个平台:Android 版由原作者独立完成,桌面端移植和双人互动版由社区独立维护。 几份实现共用同一套角色和美术资源,交互设计一脉相承。
| 功能 | 说明 |
|---|---|
| 悬空漂浮 | 缓慢浮沉 + 呼吸,动态幅度可调 |
| 拖拽 | 按住拖到任意位置,拖动时朝拖动方向倾斜 |
| 扒边 | 拖到屏幕左右边缘松手,她扒在边上、头旋转 90° 只露一个脑袋 |
| 两套皮肤 | 「饭盆头」和「女仆装」,长按她能换 |
| 点击换表情 | 每套皮肤 7 个表情循环(原样 + 开心/难过/生气/惊讶/害羞/疑惑),整张立绘切换 |
| 自动溜达 | 闲着的时候她自己爬来爬去,走一段歇一会儿;碰她/拖她/趴边时不动,可开关 |
| 小黄鸭音效 | 点击时随机播一个真实的小黄鸭吱声,可开关 |
| 长按菜单 | 「皮肤」原地换一套形象、「设置」直接进 App、「关闭」收回她 |
| 三档调节 | 悬空大小 / 扒边时脑袋宽度 / 动态幅度 |
- 安装后打开 App,点「授予「显示在其他应用上层」」,在系统设置里打开
- 回来点「让她出现」,她就浮在屏幕上了
- 按住拖动 —— 拖到屏幕左右边缘松手,她会扒在边上
- 点一下换表情,长按弹出设置/关闭
她要是过一会儿不见了,多半是被系统省电策略杀掉了。到系统设置里给她加上「自启动」和「后台运行无限制」。 小米 / 华为 / OPPO / vivo 都需要这一步,原生安卓一般不用。
装完了,桌面图标还是旧的?
这是启动器的图标缓存,国内 ROM 特别顽固。请完全卸载(不是覆盖安装)再装;还不行就重启一次手机。
点她没声音?
- 先确认设置页里的「小黄鸭音效」开关是开着的
- v0.7.1 之前的版本,在小米 / HyperOS 上会没声音 —— 音效走的是「系统音效」通道,
静音、或者关掉触摸提示音之后这条通道音量会变成 0,
play()返回成功但没有声音。 升到 v0.7.1 或更新即可 - 现在的版本跟随媒体音量,把媒体音量调起来试试
她过一会儿不见了?
被系统省电策略杀掉了。到系统设置里给她加上「自启动」和「后台运行无限制」——
小米 / 华为 / OPPO / vivo 都需要这一步,原生安卓一般不用。
点她,不换表情?
- 看设置页的「当前皮肤:饭盆头 · 表情 6 / 6」,数字不对就是素材没打进去
- 设置页打开的时候她会自动收起来(免得盖住自己的界面),这时候点不到她,回到桌面再点
安装失败 / 解析包错误?
最低需要 Android 7.0(API 24)。装过旧版本的,先卸载再装 —— 这一版的素材路径和设置项都变过。
她会联网吗?会不会偷数据?
不会,这个 App 没有申请 INTERNET 权限 —— 安卓在系统层面就禁止它联网,就算代码里想传也传不出去。
位置、大小、表情、音量这些设置只存在你手机本地。
挂着她打游戏,会被封号吗?
先说技术上做不到的事 —— 她没法开挂、没法读你的对局、没法替你操作:
| 反作弊通常抓什么 | 她 |
|---|---|
| 注入代码 / hook(Xposed、Frida、原生库) | 包内 .so 文件数 0,注入不了 |
| 读屏 / 录屏 | 没有 MEDIA_PROJECTION、没有 RECORD_AUDIO;而且悬浮窗在物理上读不到它下面的画面 |
| 无障碍自动化(读界面 + 代点) | 没有 BIND_ACCESSIBILITY_SERVICE |
| 联网上报 | 没有 INTERNET 权限,系统层面就禁止联网 |
她申请的权限只有 5 个,全部是「显示悬浮窗」这件事本身需要的。
但我不能保证任何游戏都不误判。 反作弊的规则不公开、还会变,判不判是游戏公司说了算。 真实先例是有的 —— Steam 上的桌面宠物 DesktopMate 被《无畏契约》的反作弊 Vanguard 判为违规, 它做的事和她几乎一样。
所以:风险低,但不是零。
- 别拿舍不得的账号试
- 游戏弹「检测到第三方应用」就立刻把她收起来
- 不确定就先拿小号跑一段时间
她挡视野怎么办?
- 拖到屏幕左 / 右边缘松手 —— 她会扒在边上,只露一个脑袋
- 拖到屏幕下沿松手 —— 她会趴到屏幕底下,脑袋从下沿探出来
- 想把她拉回来:往屏幕里侧拉约 12% 屏宽(趴下边时往上拉约 8% 屏高)
原版是 Android。社区把它移植到了桌面端,两套皮肤和 14 个表情都搬了过去:
| 平台 | 仓库 | 说明 |
|---|---|---|
| Windows | duhaoze2007/Baifanyu-For-Win | 原生 C++,Release 里有编译好的 .exe,下载即用 |
| macOS | duhaoze2007/Baifanyu-For-Mac | 原生 Swift,Release 里有 .dmg,下载即用 · 介绍网站 |
两个桌面版都提供了预编译包,不用自己编译 —— 想自己编也行,仓库里带了 build.sh / build.bat。
macOS 版有一个介绍网站,中英繁体三语,写了安装步骤、和安卓版的技术对照,也照实列了已知问题。
谢谢 @duhaoze2007 —— 他一个人做了 Windows 版、macOS 版和官网,还加了几个原版没有的东西: 鼠标停在她身上会停下来并弹出日期和时钟,没人理她的时候她会自己换个表情。
仓库:3108944309zpc-ctrl/baifanyu-xiaolongnv
在原版基础上加了第二个角色 —— GPT 小龙女(GPT 的拟人形象,和鲸鱼娘之于 DeepSeek 是一样的东西)。
- 双人随机互动、预设剧情对话、搭伴睡觉
- 气泡和特效都是代码画的,没有贴图
- 活动范围可调、打闹可关
- 不联网、不上传、不要账号 —— 这一点和原版一致
它带上了原版当前的全部修复(趴在屏幕下边、横屏扒边、8 个音效、被系统重启后不再自己冒出来……), 所以你两个版本都能放心装。
作者 @3108944309zpc-ctrl 也是修好原版「小米上点她没声音」那个 bug 的人 —— 修完 bug 又来加角色,谢谢他。
目前没有。不是不想做,是 iOS 上做不到同样的东西。
安卓有 SYSTEM_ALERT_WINDOW,任何 App 都能浮在别的 App 上面;iOS 不给这个能力。
唯一合法的近似方案是画中画(PiP),但 PiP 窗口的交互由系统接管 ——
「拖到屏幕边缘松手、她扒着只露一个脑袋」这个核心玩法做不出来。
iOS 上能做的是:
- 主屏小组件 / 锁屏小组件 —— 她在你屏幕上有个位置,iOS 17+ 点一下能换表情
- 实时活动 / 灵动岛 —— 你用手机的时候她一直在(iPhone 14 Pro 以上在灵动岛里)
也就是说,能做出「她在 iPhone 上的几个落脚点」,做不出「她住在你的屏幕上」。
要做的话,需要什么:
| 一台 Mac + Xcode | 编译 iOS 必须有 macOS,Windows 做不了 |
| 一个 Apple 开发者账号 | $99/年。免费账号 sideload 只能撑 7 天,每次都要重签 |
| 会 SwiftUI / WidgetKit | — |
如果你有这些条件、也愿意接手 —— 欢迎开 issue 找我。 Windows 版和 macOS 版就是这么来的:有能力的网友看到了,就动手做了。 代码我可以一起写,卡住的从来不是代码,是编译和签名。
需要:JDK 17 + Android SDK(compileSdk 36)
git clone https://github.com/LIN428924379/baifanyu.git
cd desktop-pet
# 告诉构建工具 SDK 在哪(这个文件不要提交)
echo "sdk.dir=/path/to/Android/Sdk" > local.properties
./gradlew assembleDebug
# 产物:app/build/outputs/apk/debug/app-debug.apk最低支持 Android 7.0(API 24),目标 API 36。纯 Java,无第三方依赖。
做这个项目的过程中踩了几个坑,记在这里,别人做同类东西可以少走弯路。
做桌面宠物最容易一次踩满三个坑:
- 窗口必须贴着宠物轮廓,绝不做全屏透明层。 Android 12+ 有「obscured touch」机制,不透明度高的悬浮窗盖住的地方会拦截穿透下去的触摸,用户点不到下面 App 的按钮。窗口小,这一整类问题都不存在。
- 必须带
FLAG_NOT_FOCUSABLE。 否则抖音会失焦,用户打字评论时输入法弹不出来。 - 不可见时真的要停止渲染。 在
onWindowVisibilityChanged和亮灭屏广播里停掉帧回调。屏幕关了还在postFrameCallback是纯烧电,这个 bug 极常见。
最初的做法是:保留身体,只在脸上叠一小块表情贴片。试了六种遮罩策略,全都不成立。
原因是表情图和底图是两次独立生成的 —— 五官位置差 10~25px、缩放还差 2%。于是:
| 遮罩策略 | 结果 |
|---|---|
| 大矩形 + 羽化 | 跨过头发/皮肤边界 → 额头上一块亮斑 |
| 脸形遮罩 | 不跨边界了,但偏移后的眉毛露出来 → 双眉毛 |
| 脸形 ∪ 偏移脸形 | 两条眉毛都盖住 → 又跨回头发 → 接缝 |
每个方案都是在「露接缝」和「露重影」之间换一个。 这不是调参能解决的。
最后改成整张立绘切换:每张图内部是自洽的(脸和头发出自同一次生成),问题从结构上消失。代价是素材体积变大、内存要按需解码。
教训:遇到怎么调都不对劲的方案,先怀疑方案本身,而不是继续调参数。
Android 8.0+ 用自适应图标(mipmap-anydpi-v26):一个 108dp 的画布,但启动器只显示中间约 66%。
我第一版把前景内容放到画布的 78%,结果整个背景(白底)落在可视区之外,用户看到的还是旧的深色底 —— 排查了很久才想到是几何问题。
正确做法:前景内容缩到 60~72%,保证裁完之后四周还有底。
拖到边缘吸附的判定,一开始写的是固定 56dp。但她调小之后窗口本身就窄,56dp 占了她宽度的一大半 —— 稍微靠近边缘就被吸走。
改成 min(56dp, 窗口宽度 × 25%):她越小,判定区跟着收窄。
趴边状态下只有头露出来,看起来需要一张单独的"趴姿"素材。实际上把同一张立绘顺时针转 90°、只画头部区块就够了 —— 不用多出一张图,表情贴图也能跟着旋转复用。
app/src/main/
java/com/whalepet/
MainActivity.java 设置界面(权限引导 + 三档调节 + 音效开关)
PetService.java 前台服务、悬浮窗、拖拽、边缘吸附、长按菜单、音效
PetView.java 绘制与动画、表情切换、降帧
assets/
pet_stand.png 基准立绘
pet_face_*.png 6 个表情立绘(各自按身体对齐过)
res/raw/duck*.wav 真实小黄鸭叫声(3 个音高变体)
tools/
make_duck.py 早期用代码合成音效的脚本(已被真实素材取代,留作参考)
- 表情切换时头发边缘可能有一两像素的抖动 —— 6 张立绘的身体不是像素级一致(两次独立生成的固有限度)
害羞和疑惑两个表情区分度不够,都是温柔微笑- 呆毛和长发是"硬"的 —— 目前只有整体变换(浮沉/倾斜/挤压),没有网格形变,所以动起来头发不跟着甩
- 角色形象:DeepSeek 拟人化的鲸鱼娘,出自社区创作
- 立绘与表情:由可灵 AI / 即梦 AI 生成,作者后期对齐去背
- 音效:小黄鸭叫声来自 站长素材 · 音效频道(免费下载,具体授权见该站说明);
tools/make_duck.py是早期用代码合成的版本,留作参考
⚠️ 注意:角色美术属于社区同人创作,音效来自第三方素材站 —— 本项目的 MIT 许可只覆盖代码。assets/、res/mipmap-*、res/raw/里的素材请勿商用。
代码采用 MIT License,详见 LICENSE。
美术资源(app/src/main/assets/、docs/、app/src/main/res/mipmap-*)不在 MIT 范围内,仅限个人非商业使用。
本版本增加“音效诊断 / 测试”按钮,会显示 sound_on、3 个 WAV 的 SoundPool 加载状态,以及媒体/系统音效音量,用于排查 Android/HyperOS 音频通道问题。
