普通视图

发现新文章,点击刷新页面。
昨天以前伪斜杠青年

无主之地2 MacOS 1.8.5 天邈汉化补丁与一键安装脚本

作者 Mosaic-C
2026年4月2日 21:29

背景

M4 可以流畅玩无主之地3,打完了全部 3 的内容包括 DLC 后,想起来大学时候玩的 无主之地2 ,Steam 版本支持 Mac,4k 画质玩着也没问题,最大的问题是汉化,本想将就繁体,但 Mac 版不支持繁体。

折腾

搜索后自然第一建议是某乎 Mr.One 的一篇文章,不包括莉莉丝,经过在评论区寻找,有位叫 负负得正 的大哥提供了汉化补丁,以为一切正常,直到打了两章莉莉丝才意识到没有语音

经过对比原版文件尝试得知 DefaultEngine.ini 中配置与 MacOS 版本不匹配,缺少部分参数导致语音无法加载、字幕无法显示的问题,曾经我一度认为 莉莉丝 DLC 中的 NPC 都是哑巴。。。目前莉莉丝 DLC 已经通关,测试通过。

而最大的问题其实是 MacOS 的汉化补丁安装,一开始我是使用 BeyondCompare 去对比拷贝,实在是麻烦,后来为了测试莉莉丝 DLC 语音问题需要重置游戏文件,便安排了一键汉化脚本。

使用方法

下载整合包,解压,随后打开 MacOS 终端将路径 cd 到解压后的补丁包中,修改 deploy.shgameSourcelangSource 两个变量上的文件夹位置,这个每个人不同,无法自动处理。

授权并执行即可:

chmod +x ./deploy.sh && ./deploy.sh

资源下载

无主之地2 Mac 汉化补丁 整合版下载

链接: https://pan.baidu.com/s/1kee-8OtGH7mBp1JJ3ZziKg 提取码: 9jy2

有问题请留言,以上!

从张雪机车的故事聊人生,相同之处是同是湖南人。

作者 Mosaic-C
2026年4月1日 20:28

最近最火不过于这个现实版的飞驰人生,一个好故事。在AI替代与35岁危机下的背景下,这类故事就是一束光,这是好过于任何所谓提振消费的手段。

早几年前看过一些营销号对于少年的他的采访,那时候包装的是创立凯越的经历。直至最近瓦伦丁.德比斯的双冠,才不单单是企业故事,而是把他过往的一切都丢到了网络面前,更立体了一些。

一份真正热爱的事业,从十几岁到几十岁。找不到和何为事业是困局,问题可能真出在读书上,读书时候的选择,和最终往往不同,因为毕业后的生活会教人优先去选择生存,读书被灌输的服从不利于打拼需要的野性。

痛苦带来的透彻,在这个土地上,似乎没被自己创办的公司赶出去是不完整的,背叛与贫苦是无人铺路的励志人生的必要条件。对他采访的重庆那段,是生活中无奈的缩影,人情世故?不,有能无需讲,无能多讲亦无用。

此外另一半。每个成功的故事都有,没有也会包装。柴米油盐的生活,另一半争吵,内耗伤害与认同,互相帮助的两面人生,有为则托举事业,无为则托举家庭。

刷了很多片段,就挺好的,这是迄今为止都难得一见的真励志故事,好过于太多玛莎拉蒂前面的农民工.jpg

以上!

抛弃 Zeroclaw 选择 AstrBot,简单易用,不过前提是不在意内存

作者 Mosaic-C
2026年3月27日 22:08

在折腾了两周多的版本迭代后,Zeroclaw 的最新版本直接像抛弃了 ollama 一样,所有 tool 请求一概拒绝,ollama 无法识别从而500。依旧理解最透彻的还是那个 v0.3.2,但正如这么多天修复的无数 bug,那仅仅只能作为体验。

于是,不再追求所谓低内存占用,转向 AstrBot,简单使用后便被其简单易配置的 Web 管理平台圈粉,似乎不需要我再去对着源码看各种配置,具备完整日志,自带暴露 QQ 端口,纯网页端完成模型与渠道配置。

而部署也更简单,Docker 本身使用 python:3.12-slim 作为基础,也不用再去刻意加入 Python 环境,正如标题所说,内存这方面我 8G 的树莓派自然不是太在意,但不同人不同需求:

部署参考官方文档,一个文件即可解决,配置下网络以及挂载即可:https://docs.astrbot.app/deploy/astrbot/docker.html
其他,暂时没有可说的,玩几天再来补,希望是全功能,不磨叽拐弯的,善解人意的,毕竟占用了这么大内存。

DockerFile

考虑到都有自定义镜像的需求,遂提供自动构建脚本:

资源地址

https://github.com/Anr-C/AstrBot_DockerFile

特性:每次执行 deploy.sh 将以官方最新 release 进行构建,如无更新则静默。

PS:AstrBot 非其他单二进制式 claw,且完全依赖源码,所以使用覆盖 DockerFile 的形式,不够优雅,但有效。其中 .dockerignore 也想过去排除一些无用文件,但考虑到文件不大,与官方保持同步,不进行修改。

注意:AstrBot 的 Web 面板存在于数据目录中的 dist 文件夹,虽然突兀但非多余,请勿删除。这也是和其他 claw 不同的地方。

后续

它是目前唯一能在树莓派的低性能下体验到的,流程迅速、理解正确、结果完整的,会使用代码编写/技能优先,而不是使用 web-search/web-fetch 偷懒/假装完成一整套 环境安装代码编写任务执行的 claw。

我给予极高的体验评价。

以上。

简单部署你的 Zeroclaw with Docker 喂饭版

作者 Mosaic-C
2026年3月17日 23:19

前言

正如前文所言,值得体验一把的是 Zeroclaw ,虽然推荐版本为 v0.3.2 但随着社区 BUG 修复,后面也值得更新。各种客制化适合给更高自由度的玩家,于是基础要义是自行构建镜像(不包源码修改)。

DockerfIle

基于官方 DockerfIle 移除源码构建部分,在线拉取最新 lastest 版本,仅配置运行时环境,快速,全面。中英混搭,原汁原味 + 国区风味(懒)

FROM debian:trixie-slim AS runtime

# 清华源
RUN sed -i 's/deb.debian.org/mirrors.tuna.tsinghua.edu.cn/g' /etc/apt/sources.list.d/debian.sources

# Install essential tools for agent shell operations
RUN apt-get update && apt-get install -y --no-install-recommends \
bash \
ca-certificates \
curl \
git \
wget iputils-ping \
python3 python3-pip build-essential \
&& rm -rf /var/lib/apt/lists/*

# Install uv and symlink to system path
RUN curl -LsSf https://astral.sh/uv/install.sh | sh && \
ln -s /root/.local/bin/uv /usr/local/bin/uv && \
ln -s /root/.local/bin/uvx /usr/local/bin/uvx && \
uv --version

# 强制移除 python 外部环境管理限制,允许模型自由使用 pip
RUN rm -f /usr/lib/python3*/EXTERNALLY-MANAGED && ln -sf $(which python3) /usr/bin/python

# Copy binary 下载二进制文件放在当前目录
COPY ./zeroclaw-aarch64/zeroclaw /usr/local/bin/zeroclaw

# Environment setup
# Ensure UTF-8 locale so CJK / multibyte input is handled correctly
ENV LANG=C.UTF-8
ENV ZEROCLAW_WORKSPACE=/zeroclaw-data/workspace
ENV HOME=/zeroclaw-data
# Default provider and model are set in config.toml, not here,
# so config file edits are not silently overridden
ENV ZEROCLAW_GATEWAY_PORT=42617

# API_KEY must be provided at runtime!

# 同时启动 gateway 与 daemon
COPY entrypoint.sh /usr/local/bin/entrypoint.sh
RUN chmod +x /usr/local/bin/entrypoint.sh

WORKDIR /zeroclaw-data
USER 65534:65534
EXPOSE 42617
EXPOSE 42618
ENTRYPOINT ["/usr/local/bin/entrypoint.sh"]

对于国区玩家,解决痛点如下

1、网络问题对应的容器的 Linux 源(RUN sed -i)与构建 PROXY(见 deploy.sh)。

2、各种 skill 工具需要的必不可少的 Python 环境,可在 RUN apt-get 处自由添加。

3、容器最好直接支持 gateway ( port: 42617)与 一个单独的 channel(比如 QQ 机器人, port: 42618),见 entrypoint.sh,可继续自由添加,同步端口暴露即可。

使用方法:

  • 参数配置:根据需求编辑 config.toml 文件。
  • 路径设置:查找所有出现的 /your/docker_data/(涉及 zeroclaw.ymldeploy.sh 文件),并将其替换为实际的数据路径。
  • 科学设置:确保科学网络运行在 7890 端口(构建参数 build-arg 所需),或者从 deploy.sh 中移除相关配置。

然后:

chmod +x deploy.sh
./deploy.sh

使用效果:

注:此处默认配置拉高了所有工具权限放开了大多数束缚包括调用限额,仅限本地模型进行放纵 Play否则后果将非常严重。

总之,主要源码就这么点,代码开源。

版本问题

实测 0.6.x 依旧不值得更新,文件权限/网络/config 配置无效问题,最终连 Tools xml 结构都无法解析,依旧还需要大量时间经过社区验证,简直废品

可选我客制化的 v0.3.2 究极缝合怪,特性:保持最新、放开最大网络权限、默认中文 Web 以及小问题修复(仅 Arm 64)。

使用:直接执行 deploy-stable.sh 脚本即可。

资源

完整部署脚本地址

https://github.com/Anr-C/Zeroclaw_DockerfIle_Arm64

客制化仓库地址

https://github.com/Anr-C/zeroclaw

后续

废弃该库转向使用 AstrBot,见:抛弃 Zeroclaw 选择 AstrBot,简单易用,不过前提是不在意内存

以上。

目前处于 BUG 天梯状态的低效率 Claw 还不值得作为 Gatway 使用,需及时止损。

作者 Mosaic-C
2026年3月16日 14:45

从繁杂的 Openclaw 切换到简单的 Picoclaw,再到工具看上去更高级的 Zeroclaw 的两周目总结。

闲言

Claw 是一个开放性极强的“手”,虽然有废弃 Mac 但最合适且安全的体验用法,应是 Docker,其具备理解并执行一切 Linux 开源工具的能力,在 Docker 中可以将一切权限都给他。只可惜,理想太美好,目前的进度在 30%,基于本地模型脑子不够用的情况,换成高纯度付费大模型也许能到 60%,只是随便 十几M 的 token,不值得如此尝试。

浅谈

基于树莓派 4B 8G Docker 的各种 claw 作为 gatway,Mac mini M4 32G 本地 Omlx Qwen3.5 9B-MLX-4bit 做的统一尝试:

Openclaw:知道手在哪儿,但手得弯弯绕绕把磁盘拉爆,最后极慢的给了一个结果,源码并不好改,复杂冗余,这货也不是为了 gatway 设计的,部署也不简单。

Picoclaw:知道有手,但手不记得上次手做了什么(上下文未超过)。每次都需要 call tool 、try error cmd、read skill.md 、writecode,test,try,走完这一整套流程,最后给一个错误的杂交结果。优点是日志详细,每一步都很清楚,缺点是工具链调用慢。

Zeroclaw:一直都很聪明的样子,知道用什么工具最优,执行速度最快,但结果出不来,上下文容易超限,max_tool_iterations 容易超过 100,最终静默无后文,问题应出在 try 这个过程死循环。而问题定位需要日志,缺点就是日志不够详尽,RUST_LOG=info 也不够。

总:任意 claw 都存在一个毛病,错误循环太多时,max_tool_iterations 超限。所以要求 claw 自身工具调用准确,快速,这与模型大脑无关。

在信任网络无聊的安全盾极大的阻止了可玩性,功能解禁涉及源码,所以不建议使用官方 Docker 镜像,功能少,限制多,自行构建更合适。频繁日更大大增加了不稳定性,建议停在能用的版本,按月更新。

其实最终形态应是 Zeroclaw 的工具选取,Picoclaw 的工具执行,以及他们共同的低内存占用。

这种通用 Agent 在 26 年初被资本拉入普通人世界,还是太早了一些。好在,Docker 只是需要删掉容器而已,折腾存在乐趣,就是废时间。

后续

一夜过去各 claw 均罢工 tool 调用,tool 未经 claw 拦截直接变成了 Direct Answer,经过排查定位在于 Omlx tools 协议支持存在问题,于是由 Omlx 切换到 Ollama,一改以前对 Ollama 的看法,相比较以速度起家的 Omlx,协议更通用的 Ollama 更合适,测试下来,速度也快。

最终移除了其他 claw ,选择了 Zeroclaw ,胜在响应快,工具调用不磨叽。能看到结果后的 Zeroclaw 有了新的槽点,稳定性欠佳,比如: deamon channel 会莫名其妙断开、channel restart 会失败、与模型的 tool 交互偶尔 500 Error。

Qwen3.5:9b 模型下,一轮长对话下来的耗时,仅供参考。对话内容为对此篇文章的爬取分析,这里就不贴了。

总而言之,言而总之,一切还只处于初期阶段,太勉强,则,及时止损。

一夜过去,又又又废了,推荐 Zeroclaw 停留在 v0.3.2 版本,新版本真是没有一个能用的,各种权限问题,路径问题,技能安全盾拦截问题。

水文一篇,以上。

过去的 2025 教会了我从流量品牌祛魅 – 关于消费的思考

作者 Mosaic-C
2026年1月7日 22:39

很多东西明显不合适,因为其是大牌/流量/宣传噱头而觉得其不可替代,而偏好选择,便有了祛魅。

本来也不想聊这事儿,只是最近把身边一切,从数码到日用全换了遍,才知一直活在被动选择中多累,原本可以更舒适。

手机从小米换到一加也几个月了,很好,很棒,用得很舒服,不用在意别人的评价。同一时间也从小米路由换到了中兴,内网满载很稳,发热很低,很安逸。数码这方面,以前总觉得用一套,追求整体协调性。切过来正如耳机只用索尼大法、电脑独爱 MacOS,iPad 只用苹果一样,混用也没觉得不妥,各设备选择符合自己需求的能接受的最好的,便不会有错。

那时候,小米的风评并没现在这么烂,走到今天这一步,原因很简单,一直以来小米只是能用,走高端了依旧只是能用,这就是核心矛盾。

此外还得感谢 AI 的存在,让触及很多认知之外的智商税变得轻松,比如在衣物材料方面。直白的或者大多数人都知道的例子 — “蕉内”。这个牌子火了几年我就用了几年,一直用“科技”冠以高价格,当然这市面上贴牌货大把,研创确实算得上独一档。

问题在于并不适合我,要么不够保暖,要么不够排汗散热,一直达不到他们宣传所说。一直以来是认为花的钱不够多,档次不够高,于是用 3 系的时候想着 5 系是不是会更有效。购入体验后看着那新一代变动几个点的成分配比,便可相差几百块…

直到最近到了寿命,准备再一次购入,想起现在有 AI ,将自身感受到的不适以及其成份配比交给 AI 方知其智商税之深厚,从而也通过 AI 分析也找到了更适合的成份贴身面料,品牌便不说了,毕竟每人不同,这几年类似 “蕉内” 的新生品牌也很多,选那些回购多的有真实评价的不会错的。

此外还有一众爆火的活力28、红卫等,何尝不是一种流量裹挟,用过便知道,也许反馈平平。众所周知,无功无过已是大善,太多被央妈揭开的品牌事故证明,大多数人只是在为营销买单。当然,那几年经济好,不用在这些上有所思考。

去看看那些朴实低调的,少看点广告推流,没有什么不可替代

水文一篇,以上! (略带愤怒)

从 GPT 换到 Google Gemini 的感受 – 无敌

作者 Mosaic-C
2025年12月16日 22:13

故事是这样的,最近有些技术上的新玩具,需要问 AI 来扩展知识和提速。而今天打开 GPT 提示了更新到了 GPT 5.2,其中与它对话是这样描述的:

于是晚上有点小需求,再次信它一次,前前后后纠错它,以及用它提供的方案尝试花了 1 小时。而我预估仅需 5 分钟,毕竟很多东西不是我不会只是我忘了,试到抓狂,转身打开 Google Gemini ,同样模糊描述仅纠正一次背景信息,5 分钟搞定。

结论:垃圾GPT ,我信他个鬼。

此前一直习惯 GPT ,但 GPT 自从 4B 后就开始了疯狂的胡编乱造和臆想虚构,而且在人为纠正后上下记忆错乱无章,早已痛苦不已。

听闻 Google Gemini 实力之强,今日一试,百闻不如一用,能清晰快速猜测用户需求,直击问题痛点,无敌好用。

时间就是💰,珍爱生命,远离垃圾 GPT !!!

水文一篇,以上!

小米 12X 刷全功能内核 原生运行 LXC/Docker 指北

作者 Mosaic-C
2025年11月21日 17:17

旧手机小米12X 换个盆嫌弃它太便宜,内置空间 256G 和 CPU + 12G 内存,用来做个 mini 主机不错。

内核

折腾了几天,内核出来了,直接用,仅适用于 小米12X ,理论上 Android 11 到 Android 15 MIUI 或者澎湃 OS 都支持,个人的选择是 MIUI 14 的最后一个稳定版。

项目地址:https://github.com/Anr-C/kernel_xiaomi_sm8250_mod/releases

其中分为 SkiSU 和 没有 SkiSU 版本,对于我来说,除了 Magisk 其他都不需要,所以我选择 Kernel_MIUI_psyche_NoKernelSU 前缀的。

注意:NFT 作为 Docker 新版需要的特性,如果不运行新版 Docker 是没必要去开启的。

使用方式:用 SkiSU 的客户端 或者 TWRP 刷入即可,内核开启项截图这里就不放了,Github 那边有。

容器方案

研究了好几天,看了很多项目,最后主要用酷安小绿书上的 tomxi1997 提供的懒人包:https://www.coolapk.com/feed/67916139?s=Y2Q2ZTRiZTExODUzZTM3ZzY4ZmNiY2Ezega1560,在此表示感谢。

LXC 5.0

是一开始尝试的,也是 tomxi1997 最新的 release 上推荐的 deb 版本,可正常安装运行 Docker 29.0.2 。

不便之处:LXC 容器对自身系统文件不可写,有需要就得在 Termux 中以 su 的形式,用 Termux 的 busybox 指令集去编辑 lxc 容器所在处的文件,命令很长,维护起来很麻烦。

同时也带来了另一个很麻烦的事,Docker 桥接模式需要写 iptables raw 表无法达成,没找到合适的开启特权模式的方式。以为是权限不够,转向使用 Magisk 版 lxc-5.0.2,但实测模块版 LXC 容器无法启动卡死在某处,12X 兼容性存在问题。

于是便仅留下了 deb 版本,仅需要 Linux 容器不做套娃 Docker 的还是可以试试,对于 SD 文件目录挂载,可能无从配置,未去折腾。

个人更新日志如下:

2025.11.21

1、sed 源匹配规则不正确导致部分 Linux 无法更换源问题。
2、修正缺少 env.sh 从而 LXC 面板无法进入命令行模式的问题。

DockerCore

化繁为简,毕竟我只需要 Portainer 统一管理,原生跑 Docker 运行在物理机也是可以的。tomxi1997 也提供了最终版,Magisk 刷入重启即可,也比较简单。详细描述见:https://github.com/Anr-C/DockerCore_Systemd-Ubuntu24_Magisk/blob/main/readme.txt

Docker 版本比较低,Docker Compose 版本也不高,但目前社区也就到这个版本:

:/data/data/com.termux/files/home # docker info
Client:
Version: v24.0.6-ce

已知问题:内置 Ubuntu 24 容器也如同 LXC 一样对 NTF iptables 不可写,不同的是 LXC 中的 Docker 可启动, Ubuntu 24 容器的 Docker 无法启动。

其他问题:宿主 Dcoker 容器运行时,比如 samba 对于 sdcard 挂载因 Android 权限问题不可用,大型项目因 Android 缺失其需要获取的文件而无法使用,比如 OS release 等信息文件,可以考虑补全,但终究麻烦。

网络相关则macvlan 不可用以及部分网络配置存在以下可能:

"specify mac-address per network" requires API version 1.44, but the Docker daemon API version is 1.43

尽量使用 alpine 作为底包自行搭建容器,一般无其他问题也不需要特意再套娃,已是最好选择。

个人更新日志如下:

2025.11.24

1、增加 os_release 伪造,减少错误日志输出
2、修正 daemon 单词拼写错误导致的 sd 卡日志错乱
3、开机默认启用桥接网络,用于不使用 systemd 容器,纯宿主 docker 运行情况。

2025.11.21

1、梳理项目文案,包括 Readme,sh 等。
2、docker 默认开启 Api 远程模式 2375 端口,可在 Portainer 中集群使用。

Chroot

本来不打算尝试,但处于好奇试了试。Linux 玩得多的应知道,Chroot 大多数时候用于系统急救,其具备的能力并不全,其依赖的能力来自宿主机器,仅挂载系统核心文件。于是在 Android 这边体验下来存在启动慢,卸载慢,内存地址/文件读写错误/不存在、发热大等问题,同时 Docker 在其中也无法正常启动,报内存地址错误,评价低于 LXC,不必折腾。

总评

原生跑在 Android 上的 Docker 本身为了兼容做了很多处理,不方便可以理解。可惜了这性能强了不是一点半点的闲置,本以为可以折腾点以前树莓派上因为很卡而没法折腾的了,现在看还差点实用性。

总的来说:纯玩 Docker 需要端口映射/桥接网络 就安装 Docker core for Android,需要运行各种 Linux 容器或者需要新版 Docker 能接受仅 HOST 网络就 LXC 5.0 deb。体验落地则各有缺点,需要自行摸索。

两个包都在这儿了,之所以开仓库是因为,以后可能会考虑更新下 Docker 版本,以后若有解决方案方便更新。不过小米 12X 的 4.19 内核本身就限制了很多东西,多少有点旧了,难处理。

项目地址:https://github.com/Anr-C/DockerCore_Systemd-Ubuntu24_Magisk/releases

以上。

关于 MacOS 自带 OpenSSH 兼容性问题

作者 Mosaic-C
2025年11月14日 13:43

排查了一上午,MacOS 15 真是巨烂。

这两天折腾内核,旧 X86 的 MacBook Pro 上的 ElementaryOS 虚拟机再次派上用场,之前一直在虚拟机里操作,来回隔空接力倒是也没啥,到底是心急直接 ssh 不是更好嘛,试试才发现,各种超时。

思路:

  1. 使用 ssh -vvv 查看日志,卡在新服务器都会有个 known_hosts 指纹添加的前面,等待返回握手消息。
  2. 使用 sudo tcpdump -i en0 host x.x.x.x and port 22 跟踪消息,发现 MacOS 这边的包是一直在发,而 Linux 那边防火墙没开,sshd 日志毫无反应,明显没收到包。
  3. 再就架构和软件包版本,ElementaryOS 那边的 OpenSSH_8.9p1 OpenSSL 3.0.2,寻思这不是 Ubuntu 20.X 都一样,两台服务器也是这个版本,x86 和 ARM 设备各一。
  4. 接着现象,手机 Termux,局域网中的 Linux,其他任意设备可与这台 Mac 通信,也可与那台 ElementaryOS 通信。

从版本,到 ARM 与 x86 的兼容性配置等等一系列排查下来,最终定位:

MacOS 自带的 OpenSSH_9.9p2, LibreSSL 3.3.6 与 Linux 那边的 OpenSSH_8.9p1 , OpenSSL 3.0.2 不兼容。

解决办法(也是尝试过程):

brew install openssh

再次连接则一切正常:

$ /opt/homebrew/bin/ssh user@ip
The authenticity of host 'xxxx' can't be established.
This key is not known by any other names.
Are you sure you want to continue connecting (yes/no/[fingerprint])?

至此,不更新 MacOS 26, 解决办法就只有使用 Brew 的 OpenSSH 替代,版本为最新 OpenSSH_10.2p1, OpenSSL 3.6.0 。

为了使其替代默认,优先使用,在 .zshrc 环境中添加以下代码即可:

export PATH="/opt/homebrew/bin:$PATH"

以前咋用,现在就咋用,以上。

Hide Portainer Business Upgrade Button (attribute based)

作者 Mosaic-C
2025年10月28日 10:58

更新了 Portainer 新版,这颜色方案不太适应,应该说 Upgrade 特别显眼,貌似故意为之。

为了体验更舒适,便留 Tampermonkey 脚本一份替代手工移除 Upgrade 按钮。

// ==UserScript==
// @name Hide Portainer Business Upgrade Button (attribute based)
// @namespace http://tampermonkey.net/
// @version 1.3
// @description 感谢 Portainer CE 提供出色的容器管理工具。
// 对于个人用户,社区版已足够使用。
// 本脚本仅隐藏界面中的“升级到商业版”提示,让界面更清爽。
// 脚本简单,若随版本更新失效,可再调整。
// @match *://*/*
// @grant none
// ==/UserScript==

(function() {
'use strict';

// 判断是否 Portainer 页面
function isPortainerPage() {
const html = document.documentElement;
return (
html.getAttribute('ng-app') === 'portainer' ||
html.dataset.edition === 'CE'
);
}

// 屏蔽按钮逻辑(彻底删除)
function removeUpgradeButton() {
const btns = document.querySelectorAll('button');
btns.forEach(btn => {
if (btn.textContent.includes('Upgrade to Business Edition') ||
btn.textContent.includes('升级到商业版')) {
btn.remove(); // 直接删除节点,而非隐藏
}
});
}

// 主逻辑
function init() {
if (!isPortainerPage()) return;

console.log('[Tampermonkey] Portainer detected — removing Business Edition button');

removeUpgradeButton();

// 监听 DOM 变化,防止按钮重新渲染出来
const observer = new MutationObserver(removeUpgradeButton);
observer.observe(document.body, { childList: true, subtree: true });
}

// 等待 DOM 加载完成
if (document.readyState === 'complete' || document.readyState === 'interactive') {
init();
} else {
window.addEventListener('DOMContentLoaded', init);
}
})();

已同步自 greasyfork,自行安装即可。Tampermonkey 启用生效后刷新可见清爽界面:

以上。

一加 13T 体验报告,脱坑小米,从米系 12X 换至欧系一加 13T 的醒悟!

作者 Mosaic-C
2025年10月18日 16:50

别轻易相信参数,唯有深度体验方知实际。

背景(非体验,仅前情可跳过)

又是一年双 11 ,钟爱(不得不)用小屏机器的我终于在三年后以合适价格等到了一台钟意的机器:一加 13T。PDD 百补 + 国补这价格没啥好说的,欧加电商发货安全下车,至于淘天的乌龙,文末再吐槽。

什么样的体验才会让前 5 台都是小米的人不再用小米,这里就不得不多说废话。几年前的小米 11 是一导火线:小米 11 是一件成功也失败的产品!!!,后续我不像其他人有备用机,退款后急用,高位购入 小米12X 沿用至今。12X 的标题没有浮夸,唯一的优点,手感。其他各方面的*,系统卡顿体验如米 11 的祖传,指纹识别慢,最难受的是这小米配的华星屏幕,一度导致眼睛干涩难以忍受。

于是在 8gen3 市场反馈开始好转时,有过最强烈的换机想法。小屏受众很少不受厂商待见,苹果 13 后再无 mini,赛道就很窄,看来看去只有小米数字旗舰。即便如此也是很宽,要么宽要么长。米 11 的经验让我没那么冲动,周围当时有米13、米14 ,借来一把 QQ 飞车就被劝退。参数的触摸采样率没输过哈,瞬时触摸采样 2160 Hz,上哔哩哔哩搜下就知道一言难尽。不喜米氏调度的至今大把开源调教,还有那系统一如既往,懂的都懂。

一直等到了今年国补优惠,认为是换机好时机。新的小米澎湃 OS3 赞不绝口,小米 15 映入眼帘,和一加 13T 二选一,感谢小米再次的不争气,米 15 大面积的后盖门事件。恍然醒悟,何必吊死一颗树,世上还有整片的森林。天玑 9400 线下体验同系统体验不如 8E ,更多的侧重于拍照,于是不用争。

体验篇

硬件方面

网上诟病最多的如下:

1、砍了超广角

有人对超广角是刚需,建议选天玑 9400 的小屏。个人对拍照无要求,感谢米系调教,小米 11 当年扫码都卡!几年过去硬件也吊打 12X,当年 12X 还是个影像**呢,没超广角就是照片拍不出那么宽广。能接受就不难受

后续:经过多张随手拍确认,成图 AI 痕迹有时明显,但将画面改为全屏后,裁切后的结果也是可以接受的。

2、充电不至宣称 80w

拿到手第一时间上物理工具检测过,在有这些检测设备的情况下只能 35w。去掉检测设备明显感知很快,软件测的不准确。充电和我的 12X 体感时间差不多,12X 4500mAh、13T 6260mAh,见仁见智吧。提一嘴那个自带充电头,磨砂的粗糙感有点廉价感。

3、振动马达砍了一刀

没吃过细糠,这玩意儿最低档都比 12X 强。

4、没有超声波指纹

短焦光学实测也很快,大概是 12X 的三倍,触上即开,位置和 12X 类似,无感切换。12X 是按着还得等震动 1s 多才开,偶尔还开不了,感谢米有这么好的产品,才让我不挑剔。

5、没有无线充电

想了下我除了索尼的 WF-1000XM5 和电动牙刷有无线充电,压根没有其他设备需要这个,难评。能接受就不难受

6、屏幕不太满意

这个只能表示我的容忍度其实很高,相机可以得到的答案:13T 在晚上和白天都是宽慢,亮度够则无感。12X 在晚上是细快,白天是宽快,不说了,那速度闪瞎了。拿着相机对着旁边的 iPad Pro,频闪是什么。。。完全发现不了。

后续:亮度会略微偏亮而非网上所说亮度不够,于是去设置里将白值拉低,辅以手动降低亮度。

7、没有防水

场景防水不是刚需,能抗点热气雨水就行。何况防水会失效,修一次气密性也就没了。能接受就不难受

8、找不出来了,就这样吧。

优点:

1、芯片强

8Elite 是颗好核心,能耗性能都均衡。但不可否认这几年 870 也是个好核心,不热就是好,7nm 换 3nm 鸟枪换炮。

PS:这不是 Scene,那毕竟是付费软件,且功能繁多。这是我自己手搓的简单版,也正因为是自己手搓,于是这种情况能稳住帧率才真实,自己写的软件在处理这些数据时几斤几两还是知道的。

2、电池大,续航顶

其实参数上也没觉得大 1720mAh 就大很多,之前 12X 在 24 年11 月换过电池,现在体感越来越差,保守估计仅剩 3500mAh。 3 天体验下来,大两倍绰绰有余。中规中矩,SOC 制程小 2 倍电池大 2 倍,结果自然也就是 2 倍。

PS:之所以是 6 点开始,是因为今早从6 点开始就各种探索 ColorOS 的设置项,期间包括测试游戏,测试拍照,测试耳机,测试软件使用,最后才来写这篇文。期间持续亮屏,所以掉电均匀。

最终测试结果:维持到晚上 10 点剩余 10%,开省电模式断断续续轻度使用最终维持到凌晨 4 点。省电模式也很流畅,好评+++。

后续:户外双卡+导航也依旧很顶,至此,数据传输,游戏,户外5G 续航都很满意。

3、按键不松动

以前不觉得,现在换成不是小米的设备,理解了。包容万岁

4、像苹果一样多出来的快捷键

可能很多人很早就体验过,我没有,见谅。魔改一下,很方便

5、信号好很多

新的基带,更多的 5G 频段(多 8 个 5G 频段 n48 / n66 / n80–84 / n89 ),自然比旧时代主支持 4G 的 12X 强,12X 虽然支持 4G 频段多,但 4G 基本上也是没法联网的状态。但比不上旗舰大哥一加 13,砍了一些,只能说够用。

软件方面

MIUI 是当之无愧的功能强大繁杂到大家都诟病一些莫名其妙的问题,不进行赘述,于是这里就只能谈谈切过来 ColorOS 的体感不适。

这里不好分优缺点一起混合了:

1、系统

到手出厂系统为 201,直接更新到 603 后的体验感受,即我也没太多体验出厂系统。抱歉啊,第一次知道 Android 的丝滑可以比肩我手上 iPad Pro 的 IOS 18.7。

如果说新手机出厂系统是刻意打磨,现在更新了发售后近 1 年的系统版本,转移了 150G 数据,软件也全部安装登录后,那就不能吐槽什么了,系统确实流畅。

常见的三方软件体验也都不错,至于有些则还是需要看应用本身素质,Android 15 有些也没兼容会有些错误,Android 本质上是这样的,理解则可接受。

2、软件自由度

预装的软件和 MIUI 半斤八两,澎湃是否改善不知道,两个差不多都全部可卸载,功能上开机有个增强功能选择,大概有近半百的开关项,比米系全部默认死了也不知道有还是强点。

PS:初始化时可以不用管,在设置项中 系统与更新 -> 增强服务 可重新配置。

直观感受是,ColorOS 的集中度比较高,集成度比较低,功能多为单独软件,或者说系统流畅多少有点谷歌原生的助力。米系是盘根错节,包含集成在系统里。当然后面用久了也许也能发现诟病。

3、花里胡哨的功能

ColorOS 有点花里胡哨的都是谷歌的一些原生功能的稍微改进。米的强大此刻展现无疑,数不胜数的细分“高级”功能(加了高大上的描述和视频),开了耗电,不开就像个吉祥物。大多数基础的配置项,手势操作,触感都是直接平替,米有的都有,就是没米那种可以单独拿来开发布会的比如自然声音

4、系统常用功能体验(目前体验到的)

截图

不太习惯三指区域截图的体验,或者说这个做得确实不如米。在 ColorOS 上没法直接三指后直接划区域,得等他那个缩放动画和引导指示结束后才能去划区域,按米的习惯三指后立马去划区域就会区域错乱或者被引导指示挡住无法进行划取,需要二次划区域。

图库

相册比较简陋,单独相册中无时间轴,更早期的米状态。图库编辑功能弱于米,拼接只能竖着拼接,不能横着拼接,长得差不多,但是旁边少了个切换横竖。

麦克风

昨天微信视频测试通话有噪音,电话没事,早上找到一个开关叫【人声突显】,设置项在 声音与震荡的麦克风项,下拉磁贴也有。

蓝牙

测试耳机时发现存在默认的音频模式,导致我的索尼与平时不同,重新在 Sound Connect 里的声音模式那边调回来才正常,不清楚原因。

桌面文件夹

我更喜欢米的 4 格大文件夹,这边是 9 格大文件夹,于是只能凑 3 小横条稍微有点搭配性。

桌面/负一屏卡片/主题图标

没米强大,接近原生简陋,米在这方面确实是神,什么乱七八糟的样式都有,也比较好搭配。

需要开会员,同时目前还没找到合适的,米那边是免费,设计师米那边也更多,很多设计师都不做这边的主题,难评。最后选择了开会员使用《盐OS》的状态栏、《寻界》的图标,半个 oPhone体验。最终隔天起来看着不伦不类,就把会员退了,两块钱都不行🙅‍♂️,要么最拉,要么满意,绝不将就。

字体

粗重有点不协调,不太好描述,米在这块儿确实有一手。换主题后协调很多,还是默认吧,也不是不能用。

日历

日程这些编辑、查阅体验强过米系,不会误触日期到处飞。

天气

怎么会有这么简陋的天气,看着像我大学时候写的 Demo,无法定位到街道,看个天气详情还打开浏览器跳转墨迹,绝绝子。

总评:系统软件属于能用级别,不全是好用级别。于是酷安上有大把人怀念米系软件,魔改天气、图库、编辑去给 OPPO 系使用,但结果不尽人意,终无两全

折腾项

喜欢解锁和 ROOT 的朋友,这毫无疑问是最早期米的姿态,几条命令搞定解锁 和 Magisk,市面上可以的选择不多了。不过我本身也不怎么折腾,只是为了自己写的玩具不至于荒废,这也是我果子全家桶只差一台 iPhone 的主要原因。

关于 TEE 假死问题:这又得怀念过去的米了,现在的米无法解锁也就没得选。于是微信指纹不能用的问题,不想整什么三方模块魔法使用,那就这样吧,暂未发现其他软件如此苛刻。

总评

原来 Android 也可以流畅如 iOS,原来骁龙可以调教得这么稳定,原来打游戏可以不用上散热器。这是小屏爱好者重性能轻拍照的不二选择。

总之,这价格带来的性能 + 续航我是很满意的,10 分我给 9.2,0.8 扣在软件功能细节还需打磨,一定还有我没用到的不方便

系统软件易用性方便期待 ColorOS 16 带来提升,并希望不改流畅度。

淘天乌龙

一开始我是在淘宝准备好了一切,我本来也是多年的 88VIP,开了省钱卡,蹲 8 点等结算。

算了一套美梦,最后 8 点直接来了一手涨价(此处是已经算上88VIP -500 的价格),省钱卡的 -120 也不能用了,之前购物车里能用,省钱卡可找专属客服退这倒无所谓,就是浪费精力了。

所以说 88VIP 好几年那个券都用不出去是有理由的,为什么不选简单直接的 PDD ,要来你这个凑单满减开卡乱七八糟,造孽啊。

此文写于体验三天后,更新于使用一周后,以上。

MacOS 免费 MTP 工具 OpenMTP – 3.2.25 汉化版

作者 Mosaic-C
2025年7月29日 21:08

背景

在 MacOS 上的 MTP 工具选择很少,大多太复杂需要付费,OpenMTP 是唯一满足基础且好用的软件,甚至可以用来和 Switch 大气层 DBI 进行交互。

同时作者的更新频次已经放慢,似乎没有维护需求,个人使用下来也没什么问题,这里选择将其汉化养老,更新后的源码在此:https://github.com/Anr-C/openmtp,同时分享汉化打包方法。

编译无 Apple 公证版

环境准备

该项目对于 npm 有要求,同时需要保证 node 不低于 16 :

This project requires npm version >=6.x <=8.16.0. You have version 10.9.2.

于是先安装 nvm 进行 node 版本管理,nvm 可自行了解,好用方便的多版本管理:

brew install nvm

如果之前有其他 node 环境变量请移除,并按 brew 要求在 .zshrc 文件添加:

export NVM_DIR="$HOME/.nvm"
[ -s "/opt/homebrew/opt/nvm/nvm.sh" ] && \. "/opt/homebrew/opt/nvm/nvm.sh" # This loads nvm
[ -s "/opt/homebrew/opt/nvm/etc/bash_completion.d/nvm" ] && \. "/opt/homebrew/opt/nvm/etc/bash_completion.d/nvm" # This loads nvm bash_completion

随后安装作者指定的 node 16 版本:

nvm install 16.20.2

安装特定版本 npm 8.16.0 :

npm install -g npm@8.16.0

编译链准备

环境安装完成后继续安装 yarn

npm install -g yarn

随后在项目根目录进行依赖初始化,因为要安装 electron 于是需要更改为国内镜像(阿里云):

yarn config set electron_mirror https://npmmirror.com/mirrors/electron/
# 执行 yarn 进行项目依赖初始化
yarn

打包前的修改

禁用 electron-builder-config.js 中的 forceCodeSigning:

  return {
    productName: 'OpenMTP',
    appId: 'io.ganeshrvel.openmtp',
    forceCodeSigning: false,
    // eslint-disable-next-line no-template-curly-in-string
    artifactName: '${name}-${version}-${os}-${arch}.${ext}',
    copyright: '© Ganesh Rathinavel',

同时这里也需要注释掉哨兵模式插件,项目中有两处 config.renderer.prod.babel.jsconfig.main.prod.babel.js

    // new SentryWebpackPlugin({
// include: 'app/dist',
// ignore: ['node_modules', 'webpack'],
// urlPrefix: '~/app/dist',
// configFile: 'sentry.properties',
// rewrite: false,
// release: pkginfo.version,
// }),

在 Apple 的限制下,非 Apple 开发者无法进行应用公证,从而无法编译打包正常版本,只能跳过应用公证。

修改 package.json 文件中的打包命令,追加 -c.mac.identity=null 表示不进行签名,不追加也可打包但默认会以个人 Apple 信息作为签名。

"package-mac-without-notarize-no-verify": "yarn build-no-verify && cross-env ELECTRON_NOTARIZE=NO electron-builder --config electron-builder-config.js -c.mac.identity=null build --mac --publish never",

如果需要调整其他配置,自行修改 package.json 文件,打包:

yarn package-mac-without-notarize-no-verify

随后 dist 目录下可见成果,如需查看生成的应用签名信息可执行:

codesign -dv --verbose=4 /Applications/OpenMTP.app

注意事项

打包要求不同 CPU 架构在对应架构机器打包,生成的包才能正常运行,即 x64 需要 Intel 机器,arm 需要 M 系列芯片,这点确实麻烦作者也有提及。这次勉强打出 x64 后面我就没什么兴趣了,如果有需要自行打包吧。

其他

经过安装测试,汉化目前已覆盖绝大多数场景,有兴趣的可以提汉化 PR 。

公证签名貌似 MacOS 不像 iOS 那么严格,除了初次启动并不影响什么,大多数开源软件也是没公证签名的状态,如果有为爱发电勇士可以提供公证签名那便更好了

下载地址:

通过网盘分享的文件:OpenMTP
链接: https://pan.baidu.com/s/11OgCzzv1qQs52yDBFWGPgA 提取码: fq69

以上。

Kotlin Multiplatform 调用 IOS Swift 代码指北

作者 Mosaic-C
2025年7月15日 17:55

背景

KMM 使用中有些数据需要 IOS 原生提供,被 GPT 坑了一天,最后根据 medium 一篇较新文章 30 分钟解决,GPT 一直在 c_interop 文件路径和 Xcode header 配置里无用折腾,也就是携程旅行分享的那些方案的老一套。

迭代这么久实际没那么复杂了,但官网文档依旧没法看,这里以无 Shared 模块的 KMM 为例。

理论部分

Kotlin/Native 并不直接与 Swift 交互,而是与 Objective-C 交互,由于 Swift 可以将类暴露给 Objective-C,因此这成为了一个简洁明了的桥梁。

干活步骤

定义 swift 代码

最简单的类共享示例 iosApp/iosApp/SignatureUtils.swift

import Foundation

@objc(SignatureUtils)
public class SignatureUtils: NSObject {
@objc public static let shared = SignatureUtils()

@objc public func getRemainingSignatureDays() -> Int {
//...
return -1
}
}

注意:不要在 @objc 中省略类名,使用 @objc(MyClassName) 来确保符号名称可预测、无混乱,避免增加莫名其妙失败因素。

因为是新加入的 swift 文件,Xcode 并不会识别,需要用 Xcode 打开 iosApp 项目后,在左侧资源目录对 xcodeproj 点击右键,随后找到文件添加即可。

如果不将其加入项目,编译时该类不会被编译,Kotlin/Native 也就找不到。

定义头文件以及 def

头文件 SignatureUtils.h,用于定义类的哪些方法、属性被 Kotlin/Native 使用:

#import <Foundation/Foundation.h>
@interface SignatureUtils : NSObject
+ (SignatureUtils *)shared;
- (NSInteger)getRemainingSignatureDays;
@end

def 文件 SignatureUtils.def

language = Objective-C
headers = SignatureUtils.h
package = 项目包名

简单说 def 就是定义的意思,def 文件描述详情见官网:https://kotlinlang.org/docs/native-definition-file.html

参数解析:

language :默认是 C 但这里指定为 Objective-C 是必须,理论部分已经说明。

headers :链接哪些本机代码(静态库、框架等)可以有多项,空格隔开。

package :指通过桥接方式生成的 Kotlin 绑定类存放的位置,也就是当引用共享类时导入的包。

注意:保持文件名、类名的一致性 ,勿使用 GPT 去生成,100% 错误答案。建议手写,仅需改类名、方法名和返回结果类型,继承 NSObject 是必须的固定模板,其他为固定格式。

其他:这俩不必使用 Xcode 和 iosApp 关联,仅需知道位置,比如我这里将其放在 iosApp/iosApp/Signature

配置 Gradle

需要配置的是 composeApp/build.gradle.kts ,将目录指向至 def 与 .h 文件所处位置:

kotlin {
listOf(
iosArm64(),
iosSimulatorArm64()
iosX64(),
).forEach { iosTarget ->
iosTarget.binaries.framework {
//...
}
//此处 Signature 只需辨识度高即可
iosTarget.compilations.getByName("main") {
cinterops.create("Signature") {
definitionFile.set(file(rootDir.absolutePath + "/iosApp/iosApp/Signature/SignatureUtils.def"))
includeDirs.allHeaders(rootDir.absolutePath + "/iosApp/iosApp/Signature")
}
}
}
}

使用方法和原生无差:

@OptIn(ExperimentalForeignApi::class)
fun getRemainingDays(): Int {
return SignatureUtils.shared()?.getRemainingSignatureDays()?.toInt() ?: -1
}

同步 Gradle 无报错即成功,有报错查看错误日志无用,请检查命名文件路径等细节。

完结

剩下的就是 KMM expect/actual 那套,原文中还有更多内容,但我不需要,便不赘述。

以上。

参考:Yes, Calling Swift from Kotlin Multiplatform is Easy : No Plugins, No Magic, Just CInterop.

关于 Hekate 多 emuMMC 启动项配置这件事儿-终极方案

作者 Mosaic-C
2025年6月12日 11:16

折腾的乐趣不来自折腾后的成果,而来自折腾本身,于是,需求有时候是为折腾服务的。

背景

最近 Switch2 带来了塞尔达系列的更新包,系统要求 20+,之前我将系统降到 19 后,就无法进行这次更新,主要是好奇,于是我去真实系统更新到了 20.1.1。

不过好在没什么难的,说说我的配置:原有虚拟系统 19.0.1 (分区格式),再选择虚拟系统-创建文件虚拟系统(这里没有复选确认,点了就开始无后悔药)。

理论

分区文件共存,文件文件共存都比较简单,默认都不会冲突。

  • 文件文件共存似乎要更简单,直接复制一份 emuMMC 中的 SD00(例)改名为 SD01(例)即可。
  • 分区分区共存会比较麻烦,需要使用 PC 进行分区操作,复杂后面单独讲,何况之前也测试过,文件格式与分区格式除速度外差异并不大。

随后更改 hekate_ipl.ini,复制原有启动项并由 emupath 字段区分,当然 GPT 、Deepseek 会推荐什么 emummc!path、emummc_path、emummc!id 总之别信,因为这是来自官方更新日志中的字段:

点击展开或者选择看 5 年前的原文:hekate_v520_nyx_v090_released

新增啟動時 emuMMC 選擇 使用啟動項中的 emupath 鍵將載入所選的 emuMMC。 這也可以透過使用正確的啟動 cfg 儲存位元並在 emummc 路徑偏移處寫入路徑來強制執行。請查看自述檔案以了解這些內容。 格式為: emupath=emuMMC/RAW1, emupath=emuMMC/SD00 等等。 (僅適用於由 hekate 建立的,因為它依賴於具有 emuMMC 資訊的 raw_based/file_based 檔案)。

附上我的启动项模板:

[虚拟系统-PLAY]
fss0=atmosphere/package3
kip1patch=nosigchk
cal0blank=1
emummcforce=1
atmosphere=1
usb3force=1
icon=bootloader/res/icon_payloademu.bmp
emupath=emuMMC/RAW1

[虚拟系统-LAST]
fss0=atmosphere/package3
kip1patch=nosigchk
cal0blank=1
emummcforce=1
atmosphere=1
usb3force=1
icon=bootloader/res/icon_payloademu.bmp
emupath=emuMMC/SD00

至此最基础的双虚拟系统配置完成。

说说缺点:

1、不支持选择虚拟系统来进行第二个虚拟系统的创建,默认都是以真实系统做镜像。

2、文件系统创建方式占用的 SD 卡空间会很大,默认 29G 直接做的真实系统镜像,仅分区形式可调整大小。

3、20 系统可用的 System 内存还是太少了,仅剩余 8 M,而 19 余 39M 差距并不是一点点。

4、一张 SD 卡,大气层插件并没法按系统进行区分。像达达可能需要的只是 60FPS 解锁和 amiibo,其他不那么重要,内存更加捉急。

说说好处:

1、可以在不同版本的系统玩不同 HOS 支持级别的游戏,比如,塞尔达在 20 系统解帧后体验更好。

2、各自运行在各自系统,Nintendo 文件夹各自独立,并不会冲突。

3、Pro 手柄/蓝牙音箱不用担心双虚拟系统每次都得重连,可通过大气层配置:enable_external_bluetooth_db = u8!0x1 进行共享处理,前人栽树后人乘凉。

分区与分区共存(仅尝试)

操作

多分区的系统做起来实际很简单:用 PE 下的 DG,将 SD 卡划出两片空闲空间,随便选个格式比如 EXT、FAT32,然后保存分区表,不要格式化,就形成了两个 RAW 格式的分区

这两个 RAW 和 hekate 分区工具抹盘创建的 RAW 一样,可以直接在创建虚拟系统时被识别,然后对应每个分区各创建一次虚拟系统即可。

分区表的坑

分区式的虚拟系统是一锤子买卖,定下来后,就不可后续增减。因为分区很讲究,无论如何都会是一张“错误”的分区表

为什么这是”错误”的呢,再上一张 hekate 分区读取图:

SWITCH SD 分区对应的是第 0 部分Unknown 10G 对应第 1 部分Unknown 15G 对应第 2 部分

而这个顺序是 hekate 默认做分区时的顺序,从左往右,从而导致了我在加分区时,经历了这样的变化:

  • 如果我再加一个 Unknown 18G 在 Unknown 10G 的左边,毕竟只有 Unknown 10G 左边有空闲对吧,思路没问题。
  • hekate 就会变成 Unknown 18G 为 第 1 部分,Unknown 10G 对应第 2 部分,Unknown 15G 对应第 3 部分。
  • 因为 hekate 每一个部分对应的是 RAW1 RAW2 …类推,那么此时要被识别为 RAW3 只能选第 3 部分,因为 1,2 部分已经被之前的系统占用了地址与唯一 ID
  • 最后不管是选第 1 部分 重做(ID 冲突了,旧的找不到了),还是选第 3 部分重做(旧的真实文件分区直接被覆盖),都会是失败的。

这并非三分区的问题,二分区也会,我这里只是用更加复杂的举例了。如何解决?假设分区表倒过来

此时理论上,空闲空间在 unknown 10G 右侧,增加的新分区自然而然成为了第 3 部分,也对应了 RAW3 并具有新的唯一 ID。

但不幸的是,此路不通。

1、首先 RAW 分区不能是最左第一个分区,因为第 1 部分会无法被识别,原第 2 部分会成为第 1 部分,SWITCH SD 因此成为第 2 部分,推测是为 Linux / Android 留的 EFI 引导分区

2、位置问题好解,前面做一个空分区,虚拟系统就可以创建在我们想要的位置。但创建完成启动就会发现,这个顺序做的虚拟系统无法启动。不是大气层报错,而是 hekate 根本找不到虚拟系统所在位置。

所以分区-分区式 是一锤子买卖,一开始就做好,永不变动。hekate 必然有他这么做的理由,不必折腾。

这套方案致命的弱点除了无法变动,同时 hekate 并不支持备份第二分区,也就无从恢复,当然可以整盘 DD ,可几百 G 的空间 DD 很麻烦。

双分区示例:

其他细节

缩小 USER 分区

因为是虚拟系统,都在 SD 上,内置 USER 空间太大不方便备份也不方便移动,有必要了解这部分。

缩小 USER 分区的原理:按磁盘地址截断。意思就是,比真实系统小的空间,或者任何不由 hekate 创建的RAW 都会视为修改过的分区, 会对应文件系统碎片不全的文件映射(文件记录在,文件实际上不在)。

这也是分区类型多次操作后将导致文件系统交叉读写错误的来源。从而虚拟系统启动后一堆游戏打开/安装错误,碰到对应不存在的碎片地址大气层就直接崩溃

解决办法是:在设置中初始化主机或直接 daybreak 降级恢复出厂。NS 的虚拟系统创建没有 DG 那种划配空间时的文件碎片整理功能,这也是 NxNandManager 不清除 User 分区数据就无法缩小的原因。

NxNandManager 缩小 SD00 式虚拟系统很简单,5.2 版本即可,支持 20.1.1 最新系统:https://github.com/eliboa/NxNandManager/releases,教程网上有很多,这里不赘述。

降级失败/初始化失败问题

另外值得一提的是,多系统因为是一张 SD 卡,共用一套大气层,从而产生的文件可能会导致某个系统在降级/恢复初始化后启动蓝屏。从而无法进入初始化流程,浅层的解决办法是:降级完成后,启动之前,将大气层还原到初始状态,不过这样治标不治本。

如果去检测 FAT32 文件系统,会发现频繁出现文件无法删除/一直占用等问题,DG 会提示文件交叉读写错误/分区损坏。这时候用 DG 检查磁盘坏块,就会得到答案。(注: DG 的坏块检测原理决定了对于不支持的磁盘格式会误判,需格式化对应位置为FAT32后单独对该区检测)

解决办法是:整盘格式化为 FAT 32 后再对虚拟分区那块地址检测坏块,如果不存在错误,就只是折腾时 hekate 多次来回创建虚拟系统累积导致的文件系统错乱。如果依旧存在错误,很不幸,SD 已经被折腾坏了,尽早换卡。

终极方案总结

经过多次双分区尝试,总结最合适方案为 10G RAW1(分区式主力 19.0.1)+ 8G SD00(文件式备用 20.1.1)的组合,好处如下:

1、最适合备份/恢复,RAW1 可直接通过 hekate 备份/恢复,单分区的情况下,换卡也可还原。SD00 直接拷贝即可备份/恢复。

2、最适合动态扩增,RAW1 虽然依旧是一锤子买卖,但 SD00 可通过 NxNandManager 进行空间缩小或者扩大,文件形式也不会存在分区那种 ID 或者物理地址覆盖问题。

文件式缺点:无法开启 USB 3.0。

当然有人会疑问为什么不是 文件 + 文件,很显然 FAT32 文件系统交叉读写导致的磁盘坏柱一旦发生,就不会是简单的修复可以还原,MacOS 操作下这类事件很常见。

后续

虚拟 19.0.1 维持不变,虚拟 20.1.1 已通过 daybreak 更新至 20.5.0,主机正版系统维持 20.1.1(使用时拔除 SD 卡),实测三系统互不影响。

在给朋友的 续航版硬破机器 处理多系统时发现,硬破使用 sdloader.enc 引导时不支持 SD 文件进行启动,于是往往硬破自带仅能 单分区破解正版破解 形式的双系统。

以上。

参考:

Multiple emuMMC setup, including restoring a clean NAND for online use

Hekate v5.2.0 & Nyx v0.9.0 發佈啦!

使用 Docker Devkitpro 编译 Switch 插件 – 例 sys-clk 2.0.1 汉化版

作者 Mosaic-C
2025年6月4日 12:19

背景

Switch 很多插件已经稳定运行了几年不再更新,虽然英文简单,但中文看起来确实舒服点,于是自己动手吧。

Sys-clk 简介

Sys-clk 是一个超频软件,项目地址:https://github.com/retronx-team/sys-clk,而网上有些人打包出来的汉化版要比原版大一倍,默认什么都不做的情况下,打开游戏就会死机黑屏,就比如:

左侧是我自行打包的,右上的原项目 release 2.0.1 版本,右下,不提也罢,B站上很多诸如此类不知来源的软件包。对我而言,我会选择与官方二进制文件进行对比,仅做字符修改的,我才会认可。

编译和打包这类 switch 软件很简单,会用 docker 就行,甚至也不用去管什么平台差异,更不会污染本机环境。

准备 Docker 环境

对于 Switch 我们需要的环境是现成的,默认就好:

docker pull devkitpro/devkita64

创建一个容器,并把 sys-clk 的源码挂载到容器的 /sys-clk

docker run --rm -it -v path/to/sys-clk/:/sys-clk devkitpro/devkita64:latest /bin/bash

此时会进入容器的终端,配置一下环境变量:

export DEVKITPRO=/opt/devkitpro
export DEVKITARM=$DEVKITPRO/devkitARM
export DEVKITA64=$DEVKITPRO/devkitA64

随后切入挂载点,给 build.sh 执行权限,然后执行即可:

cd /sys-clk
chmod +x build.sh
./build.sh

编译时间很短,不过几秒钟,实属再小不过的项目。结果输出在 overlay/out 目录下,全套文件(包括补丁、manager)则在 dist 目录下。

注:此处编译为 sys-clk 官方提供的 build.sh,部分项目是直接 make,需自行探索。

关于汉化

对于这个项目,有点计算机底子的应该都不会觉得难,何况还有字符搜索,sys-clk-manager.nro 我用不着,也许需要的朋友可以自行尝试。

这里附上汉化 sys-clk-overlay 的 diff,自编译的可以直接拿去用(git apply update.patch),以及生成的成品 sys-clk-overlay.ovl,需要自取:

下载链接

链接: https://pan.baidu.com/s/1VRXrCekklrFcfKSDYODcyA 提取码: kx8i

注:需配合官方的 patch 补丁,不要乱用他人补丁,认真对比文件二进制差异以及文件大小,小心被人植入后门。

软件上不会有关于我的信息,我喜欢干干净净,有问题请留言。

以上。

使用 jpackage 将 JavaFx jar 封装为 MacOS DMG 安装器 – 例 NS-USBloader

作者 Mosaic-C
2025年6月3日 11:26

常用 Switch 的朋友,可能知道有一个工具叫 ns-usbloader,github 地址:https://github.com/developersu/ns-usbloader

因作者仅提供了 jar 运行方式,无法在启动菜单留存,使用略有不便,于是就自己打个包套个壳。

适用于所有 Java 环境下双击 jar 就能运行的程序。示例:

jpackage \
--name NS-USBloader \
--input ./jar \
--main-jar ns-usbloader-7.2-m1.jar \
--type dmg \
--dest ../ \
--icon ./app.icns \
--app-version 7.2 \
--jlink-options "--strip-debug --compress=2 --no-header-files --no-man-pages"

可编辑的部分:

--name       应用程序名
--input jar 所在位置,打包时会将该文件夹内所有文件打包
--main-jar jar 文件名
--type dmg 打包为 dmg,当然也可以是 app-image 等其他
--dest 输出目录位置
--icon 图标位置,MacOS 的图标格式为 icns
--app-version 版本号
--jlink-options 本来是想精简下成包体积,但 DMG 特有的压缩算法,只能图个安慰

由于 jpackage 会默认打包完整的 jre ,好处不用配置环境,坏处文件体积略大,尝试了自打包,解包再打包,总而言之,言而总之,jpackage 自带的打包算法已经是最优。

关于生成的 APP:可在 NS-USBloader.app/Contents/app 中找到 Jar 对比 github 上的原文件。此外,文件结构应清晰明了无多余文件:

/Applications/NS-USBloader.app ❯ tree -L 3
.
└── Contents
├── Info.plist
├── MacOS
│   └── NS-USBloader
├── PkgInfo
├── Resources
│   └── NS-USBloader.icns
├── _CodeSignature
│   └── CodeResources
├── app
│   ├── NS-USBloader.cfg
│   └── ns-usbloader-7.2-m1.jar
└── runtime
└── Contents

8 directories, 7 files

包括生成的安装器,也是精细布局过的,倒是有点不像 Java 的风格。

打包的 NS-USBloader-7.2.dmg 也分享一下,也许有朋友用得着。

下载地址

链接: https://pan.baidu.com/s/1iMjTJ3An1jxU243OR3wzww 提取码: ts9f

免责声明:请勿从其他地方获取该安装器,因此遭遇的风险自行承担,图标资源来自 GPT 自动生成。

以上。

关于 Switch emuMMC 虚拟系统 Downgrade 降级那件事

作者 Mosaic-C
2025年5月28日 10:26

背景

临近 Switch2 发售,想买的游戏很早就买了,一直在吃灰,既然大限将至,就发挥下余热好了。同时发现 Switch 20.0.1 对比 Switch 19.0.1 存在反向升级,这一点在大气层的更新日志中有提及。

意味着如果在用 Ultrahand 配合 FPSLocker 的那些朋友不会很快乐,举例就是塞尔达从掉帧森林变成了卡帧森林,最终在退回 19 后感受到了明显的提升。

其他的一些补充废话

稍微研究了下大气层那套,这里不考虑描述那些不难但麻烦的事儿。整合包网上很多,存在无用文件/软件是正常的。至于纯净版,熟悉 Linux/ Android 的朋友,不,应该说熟悉 MacOS 黑苹果的朋友,自配起来应该不难。

毕竟一句话就是:atmosphere + hekate + sys-patch + ultrahand(if u need)

老任这个系统,是 Linux 的远房亲戚,系统分区很有特色,分区格式在 Mac/Win/Linux 三大操作系统下均无法有效驱动,不必折腾,Hekate 相关工具已经足够(可类比 Android 的 TWRP)。

降级提醒

首先,必须是大气层 SD 卡上的虚拟系统,正版不要想。虚拟系统为真实系统的 COPY 副本,降级失败与否,与虚拟系统是文件夹形式单独分区形式无关。非要说就是文件夹形式略慢,同比创建 emuMMC 文件夹形式大概慢 1 分钟,原因自然也好理解不多赘述。

降级需要清除系统数据,不像升级那般无脑,如果是保留数据的情况下,开机必蓝屏。

降级思路 – 先备份

根据风险,在做完虚拟系统后,应对卡带的那些 DLC 和 UPDATE 进行备份,当然你也可以只备份存档数据,然后全装那些整合资源。我这里是为了保留卡带的更换快乐。

游戏补丁/更新备份工具

DBI(https://github.com/rashevskyv/dbi)这是一位俄国朋友开发的工具,最后一个支持英文的版本号为 658,至于最新版为何不支持英文,听闻是对战争的一种抵抗。

想要中文?只能说习惯就好,作者也提供了菜单对照表,学学俄语也不错。

主界面存在三项菜单:

Просмотр установленных игр                 Browse installed applications
Просмотр тикетов                           Browse tickets
Просмотр сохранений                        Browse saves

Browse installed applications 进去,可按 X 多选 dump 的应用,最后按 + 选择 Dump to SD Card。备份会存放在 SD/switch/DBI/dumps(DBI.nro 存放在单独文件夹的情况)。

Browse tickets 进去,可按 X 多选 dump 的票据,导出位置同 applications,实测这个最后都会被替代为 Common ticket,导出的意义不大。

至于 Browse saves 这个功能,试用后,我选择 JKSV 替代,更方便恢复。于是这里 DBI 只承担 dump NSP 的作用。

存档备份工具

JKSV(https://github.com/J-D-K/JKSV),这个很简单,进去界面按 Y 等待备份完成即可。备份目录在 SD 卡根目录 JKSV。恢复时选择账号后选择游戏,按 A 恢复即可。

用户账户备份工具

linkalho(https://gbatemp.net/download/linkalho.38822/),这是一个少有人提起用于备份的工具,都只说用来离线绑定任天堂账号。实际上他的备份用户账户在恢复时,也可以直接恢复原绑定状态,非常适合用于降级。

备份时直接点备份即可,恢复时按要求放在 switch/linkalho/restore/restore.zip,字符不可有任意差别。

注:用户账号属于核心数据,每次备份恢复均需要重启,以及不会备份账号游戏时长记录相关数据。

准备降级

固件从哪儿下应该都知道,zip 解压后文件夹名改 firmware 丢 SD 卡根目录,进入虚拟系统,用 daybreak 选择 firmware 进行不保留数据降级即可。

关于 MacOS 无法识别固件包问题,原因都在.DS_Store,需要使用命令清除这些垃圾。

find /Volumes/SWITCH\ SD/firmware -name ".*" -type f -delete

不出意外,便可正常识别固件。

注:从 20.0.1 退 19.0.1 为小版本降级,BOOT1/BOOT2 可兼容,大版本变更可行性这里无法确认。

恢复流程

先用 DBI 安装那些 Dump 的 NSP,再用 linkalho 恢复用户账户,最后用 JKSV 恢复存档。

试错总结

这也是降级失败两三次后的经验,先后验证失败原因:

  • 是否为分区格式驱动选错 ❌ 大胆选 fat32+exfat 即可
  • 是否因为 emuMMC 创建形式不同 ❌ 仅速度略差
  • 是否因为用户数据影响 ✅ 使用工具备份并在降级后恢复数据

主打一个折腾的乐趣,如有问题请留言。

后续

经过体验,退回 19 后,整整增加了 30M(老任少占用 10M + 大气层优化的 20M)内存用于维持 UltrahandFPSLocker 等模块。

在塞尔达掉帧森林环境下的 60 帧目标值下有着较好的表现,虽然最终实测从 15 提升至 30 ~ 40 FPS,它已经很努力了

以上。

2025 Kotlin Multiplatform 感受浅谈,跨端应用是否可以考虑 KMM

作者 Mosaic-C
2025年4月30日 18:20

背景

这几天整了个小 IOS 需求,大致体验了下双端开发,目前已经接近完工,涉及主要是 SQLite、IO 以及最常见的 UI,未涉及网络。理论上网络诉求远大于本地端,体验应当不太差(仅理论)。

之前的同事(两年前)开发过一款 KMM 的网易云,但后续我并未尝试,因为懒得踩坑,现在 BETA 。从新手的角度看,还算顺畅。

感觉直到 KMM ,才意义上的符合了当初的一个 Activity,因为一旦越界,就不是一个单端开发能搞定的了,一切行为围绕 ComposeView,以及 Gradle 与 Kotlin 官方文档。

一些流程

在构想一个功能的时候,脑子里第一件事还是停留在“是否支持 KMM”,毕竟想要通用,等于大换血。GPT 能给不少助力,至少能得到一个“看上去可行与否”的答案。

随之便是尝试找对应的 lib,因为 KMM 核心在于 Kotlin 与 Compose 的通用,版本太新了会崩溃,太旧了也会崩溃,不支持的便用不了,此刻崩溃对于版本号⚠突然不再显得刺眼。

找得到 lib 还好,找不到的呢?KMM 迭代了这么久,自然是有组合拳,定义一个 expect 预期 :

expect fun loadDatabaseBuilder(): IDatabaseBuilder

两端再分别来个 actual 实现:

actual fun loadDatabaseBuilder(): IDatabaseBuilder = DatabaseBuilder()

这个组合拳支持的部分,按属性、方法,类排,进程到了 object 这里会给个提示 are Beta:

'expect'/'actual' classes (including interfaces, objects, annotations, enums, and 'actual' typealiases) are in Beta. You can use -Xexpect-actual-classes flag to suppress this warning. Also see: https:// youtrack. jetbrains. com/ issue/ KT-61573

我不知道 Bate 和正式的区别有多久,毕竟 Google 还有很多东西 3 年前是 alpha 现在还是,并非停止维护也是一直在更新,就是这个正式太难了。

总的来说,两端依旧在用 Kotlin。脱离了 UI 的部分,Kotlin 才开始不再像 Kotlin,在涉及到 IOS 的原生部分(文件、plist、日志)时,NSxxxxxxx 之类的特定代码,会变得常见。是单端需要花时间去查找的部分,例:

@OptIn(ExperimentalForeignApi::class)
private fun documentDirectory(): String {
val documentDirectory = NSFileManager.defaultManager.URLForDirectory(
directory = NSDocumentDirectory,
inDomain = NSUserDomainMask,
appropriateForURL = null,
create = false,
error = null,
)
return requireNotNull(documentDirectory?.path)
}

U1S1,这时就有了点 AIDL 的味道,做过系统开发的都应知道,GPT 说 Flutter 也是一样,不过上面都是小问题,习惯了就好。

大问题在哪儿呢,就是这个 KMM 用的人确实不多。

1、最常见的 toast 场景 ,Github 上被 GPT 推荐的库 Star 不过百,而且相当的新。当然也可能是 toast 在 IOS 那边太丑了,大家选择各自实现

2、文章基本停留在 2022,和 2024 年底。

这个时段很有意思,2022 那批文基本上包含了一个 Shared,以至于现在问 GPT 回答总是带 Shared 的错误答案。

图中是 Kotlin Multiplatform Wizard :https://kmp.jetbrains.com/

而 2024 年底,是 K2 和 Share UI Beta 开始从而将我拉进坑的时间,这个项目初始化是无 shared 目录的。

这样理解一切就合理了,毕竟时间超短,加上全球经济形势,恐难以出现现象级的社区支持,何况大国之争下,鸿蒙成了强推,好不好用另说,得先遥遥领先

其他,貌似技术上没什么好说的。基本上逻辑都写在 commonMain ,像开发 Compose Android 一样去写就好了,只是需要注意很多常见的 java 包都不再支持,需要换成 kotlinx,简单如 datetime 也不能用 currentTimeMillis 了事。

BB 完了

如果是新项目,如果是 Android 背景的独立开发者,如果是一个不需要什么黑科技的普通 APP(不需要什么底层支持),只需两端 UI 同步,目前的 androidMain、commonMain、iosMain 已经很顾名思义,可以尝试,所见即所得。

和 Flutter 似乎没有比的必要,思路流程差不多,何况是同一个爹。至于 Flutter ,目前群基本安静了,正如目前的中小企业现状。。。不是,难道 KMM 的核心不应该是“不用新学”?

同时吐槽下 IDE 性能,M4 32G 的配置,开发起来还是有点卡卡的,能瘦瘦身吗?还要吐槽下 Apple, 不当 Apple Dev 不知,开发 IOS APP 都得先花 688 交会费才能玩,不然 ipa 打包资格都没有,dev 7 天就得重签,企业也才 1 年,也难怪欧盟一直搁这制裁。

以上。

为了 K2 compiler, 将 Kotlin 更新至 2.0.0 需要做的事儿

作者 Mosaic-C
2025年4月28日 12:04

最近有个开发 IOS 的小需求,想看看 Compose 的 Multiplatform 出新手村没,然后看到评论区一堆人在 IDEA Multiplatform 插件评论区 call 咩有 K2。疑惑 K2 是啥玩意儿,于是在官网看到了”遥遥领先式“宣传手法:

The new K2 compiler is enabled by default starting with 2.0.0. For more information on the new features provided in Kotlin 2.0.0, as well as the new K2 compiler, see What's new in Kotlin 2.0.0.

Performance improvements

To evaluate the performance of the K2 compiler, we ran performance tests on two open-source projects: Anki-Android and Exposed. Here are the key performance improvements that we found:

The K2 compiler brings up to 94% compilation speed gains. For example, in the Anki-Android project, clean build times were reduced from 57.7 seconds in Kotlin 1.9.23 to 29.7 seconds in Kotlin 2.0.0.

The initialization phase is up to 488% faster with the K2 compiler. For example, in the Anki-Android project, the initialization phase for incremental builds was cut from 0.126 seconds in Kotlin 1.9.23 to just 0.022 seconds in Kotlin 2.0.0.

The Kotlin K2 compiler is up to 376% quicker in the analysis phase compared to the previous compiler. For example, in the Anki-Android project, analysis times for incremental builds were slashed from 0.581 seconds in Kotlin 1.9.23 to only 0.122 seconds in Kotlin 2.0.0.

For more details on these improvements and to learn more about how we analyzed the performance of the K2 compiler, see our blog post.

原文:https://kotlinlang.org/docs/k2-compiler-migration-guide.html#performance-improvements

简单说就是:编译速度提升 94%、分析速度提升 376%、初始化阶段速度提升 488%。

文章发布日期也才 4 天前,这次赶了个早,从标题看,主要是利好 Multiplatform ,不过无所谓,需要 Kotlin 2.0.0,也算专业对口,这就给自己的 APP 安排。

如果经常用 Android studio 自动更新的朋友,一定会发现触发编译必有错误,当你费尽心思调顺后,warning 又会将你指向这俩文档,意思要用 2.0.0 必须整这么个 compiler :

https://developer.android.com/develop/ui/compose/compiler?hl=zh-cn

https://www.jetbrains.com/help/kotlin-multiplatform-dev/compose-compiler.html

但不好意思,一路按他的流程 next 下来,只会是 Error 、Sync failed 等常见组合拳,我习惯称为“水土不服”。

总的来说,就是他们在做 kotlin、gradle、compose 的分分合合,没说的那么简单,也没那么复杂。

Plugin 的分分合合

一句话:增加 compose-compiler-gradle-plugin ,移除 kotlin-gradle-plugin 换为 kotlin.android.gradle.plugin

对于 plugin 的管理,可能一些老旧项目切不过来,这里分两个版本。

非 TOML 管理版本

在用 classpath 的那个根 build.gradle.kts 追加一个 compose-compiler-gradle-plugin ,移除 kotlin-gradle-plugin,换为 kotlin.android.gradle.plugin,同时需要更新下 gradle 版本 ,完整版:

classpath("com.android.tools.build:gradle:8.9.2")
//kotlin 2.0+
classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:2.0.0")
classpath("org.jetbrains.kotlin.android:org.jetbrains.kotlin.android.gradle.plugin:2.0.0")
classpath("org.jetbrains.kotlin:compose-compiler-gradle-plugin:2.0.0")

TOML 管理的版本

这里就不多说了,根 build.gradle.kts ,移除 kotlin-gradle-plugin ,换为 kotlin.android

plugins {
alias(libs.plugins.org.jetbrains.kotlin.android) apply false
alias(libs.plugins.compose.compiler.plugin) apply false
}

libs.versions.toml 文件:

[versions]
kotlin = "2.0.0"

[plugins]
org-jetbrains-kotlin-android = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" }
compose-compiler-plugin = { id = "org.jetbrains.kotlin.plugin.compose", version.ref = "kotlin" }

然后

既然增加了一个 plugin,自然在 module 也需要配置,比如 build.gradle (若是 kts 自行按 kts 写法):

plugins {
...
id 'org.jetbrains.kotlin.plugin.compose'
}

不多吧,就这点东西,可以成功同步了。这段代码记得删了:

composeOptions {
kotlinCompilerExtensionVersion = "1.5.14"
}

官方文档提到的 Compose 编译器 Gradle 插件配置选项,也可以加了:

android { … }

composeCompiler {
    reportsDestination = layout.buildDirectory.dir("compose_compiler")
    stabilityConfigurationFile = rootProject.layout.projectDirectory.file("stability_config.conf")
}

PS: Compose 稳定性的配置文件 stability_config.conf 还请手动创建,这部分的配置见:

https://developer.android.com/develop/ui/compose/performance/stability/fix?hl=zh-cn#configuration-file

Kotlin 官方推荐的注解处理工具:KSP

按上面的流程,可以编译了,但编译一下就会发现:

w: Kapt currently doesn't support language version 2.0+. Falling back to 1.9.

Kapt 仅支持 Kotlin 1.9,且进入了维护阶段,而有个新东西,com.google.devtools.ksp 已经先行了很久,于是

同样在 classpath 的那个根 build.gradle.kts 增加(toml 的更简单就不贴了):

//replace kapt
classpath("com.google.devtools.ksp:com.google.devtools.ksp.gradle.plugin:2.0.0-1.0.24")

在 module 中的 build.gradle 更换 ‘kotlin-kapt’ 为:

plugins {
// byby kapt
id 'com.google.devtools.ksp'
}

然后移除所有的 kapt 配置项,将 dependencies 中的 kapt 替换为 ksp。Kotlin 是 2.0.0 ,Ksp 则也只能是 2.0.0,否则会甩你一堆“版本太高了”,具体版本见:

https://central.sonatype.com/artifact/com.google.devtools.ksp/com.google.devtools.ksp.gradle.plugin/versions

不过也就需要一直忍受 A newer version of com. google. devtools. ksp than 2.0.0-1.0.24 is available,但不好意思就是不能升。

无了

上面就是 update to kotlin 2.0.0 需要干的简单事儿了。

试用了一把,本来就是 M4 ,编译实在是没什么太多感受,以前 Intel 转 2/3min 的东西,现在不过 25s/1s ,硬件决定的还是多一点

不过别失望,折腾是值得的,Kotlin 2.0.0 随之而来的 Compose 生成的 Debug 应用流畅了许多。

后续

既然是大更新,自然免不了要适配,目前初步测试,触摸/动画事件的改变较多,已知:

1、awaitHorizontalTouchSlopOrCancellation 行为进行了变更,事件消费后其他控件依旧可消费,不如直接使用 detectHorizontalDragGestures 可靠,像是刻意的规正,扩展进一步收缩。不过也许是BUG,毕竟 Kotlin 1.9 并没问题。

2、API 变更,这个官网有披露,animateItemPlacement() 变成了 animateItem()。

既然要适配,于是后来一口气直接更新到最新的 2.1.20,Debug 版 APP 流畅度居然够得着正式版,相当的离谱!!!当然敢这么改,也是自 TOML 管理后,只需要改改 TOML 文件的 Version 不用到处找代码来的方便。

建议仅 try try dev,毕竟大项目免不了各种自定义事件,一个个调未免太费时。

以上。

❌
❌