WinLand:基于 WinUI 3 与 .NET 10 的 Windows 桌面灵动岛插件项目

Windows 灵动岛(Dynamic Island)桌面应用 · WinUI 3 / .NET 10 · 支持插件与插件市场

分支1Tags2

该项目正在开发中!

WinIsland — 给 Windows 的灵动岛

Release Downloads Platform .NET Plugin API

一个常驻桌面的悬浮胶囊:平时安静地待在角落,展开就是媒体控制台、充电与硬件看板。

所有内容都由可热插拔的插件提供,并配有社区插件市场。

想给灵动岛加个功能,但不会写代码? 把 WinLandPluginSkills 技能装进你的 AI 助手(Claude Code / Command Code 等),然后用中文说一句需求——它会带你从零做到上架插件市场。 见 插件开发 → 路线 A。


它能做什么

展开态:主岛 + 队列卡片

平时它是一枚安静的小胶囊(宽度不超过 170 逻辑像素),鼠标移上去就展开成一座「岛」:上方的卡片是队列—— 每个在报事的插件各占一张;最下面那张是主岛——当前优先级最高的内容,这里是正在播放的音乐。

紧凑态

紧凑态:正在播放 · Windows Fluent 风格(Desktop Acrylic 磨砂玻璃)

点击胶囊可以做当前内容的主操作(打开播放源应用、刷新天气、查看详情)。

功能亮点

  • 两种形态 —— 紧凑胶囊 ↔ 悬停展开(主岛 + 最多 3 张队列卡片),展开/收起带形变动画
  • 两种外观 —— Apple 纯黑胶囊,或带系统材质(Acrylic / Mica)的 Windows Fluent
  • 两种摆放 —— 贴屏幕顶部悬浮,或真·嵌进任务栏条带(自动避开任务栏图标、跟随自动隐藏、被压住时自愈置顶)
  • 插件系统 v2 —— 依赖隔离、热插拔、超时与异常防护、注册项全部回收
  • AI 友好 —— 配套 winland-plugin-maker 技能:用中文说一句需求, 就能让 AI 从零写出插件、装进你正在用的 WinIsland 实测,并投稿上架市场(全程不用懂编程)
  • 插件市场 —— 整表一次请求、多镜像回退、安装前强制校验 SHA-256
  • 开箱即用 —— 内置「正在播放 / 充电监控 / 发送消息」三个插件,它们同时也是最好的示例代码
  • 干净 —— 无边框、真透明、点击穿透(形状级)、每用户安装不需要管理员权限

插件一览

内置插件(随程序一起装好):

插件 小岛显示 展开后 说明
正在播放 封面 + 曲名 + 跳动音条 封面、曲名 / 歌手、进度条与上一首 / 播放暂停 / 下一首 基于 Windows 系统媒体会话(GSMTC),任何播放器都能接管
充电监控 电量环 + 百分比 + 充放电状态 实时充电功率曲线、电池状态 用 Windows.Devices.Power 读电池报告,插拔时自动弹提示
发送消息 —(没有常驻内容) 手动推一条消息 / 自定义 XAML 控件到岛上 用来验证、演示和对接自己的脚本与自动化

社区插件(在「设置 → 插件市场」里一键安装):

插件 小岛显示 展开后 说明
天气小岛 天气图标 + 温度 今天 / 明天 / 后天三天预报 数据来自 Open-Meteo,不用注册也不用填密钥
硬件监控 CPU 占用 + 上下行网速 前台窗口 FPS、CPU / GPU 占用与型号、网络吞吐 想要 FPS 时需要以管理员身份运行

快速开始

系统要求

  • Windows 10 1809(build 17763)或更高版本,x64 / ARM64
  • 安装包是自包含的:.NET 运行时与 Windows App SDK 都在包里,不用另外装
  • 安装到 %LocalAppData%\Programs\WinIsland,全程不需要管理员权限

安装

到 Releases 下载 WinIsland-<版本>-x64-setup.exe(或 -arm64-),双击安装即可。

启动后:

  • 胶囊出现在屏幕顶部中央,或嵌进任务栏(由「设置 → 通用 → 位置」决定)
  • 双击托盘图标打开设置,右键托盘图标可以显示/隐藏灵动岛、退出
  • 默认「空闲时隐藏」:没有任何插件在报事时自动收起,有内容再出现

从源码构建

# 需要 .NET 10 SDK;Windows App SDK 由 NuGet 还原
cd WinIsland
dotnet build
dotnet run

仓库里没有 .sln,直接构建 WinIsland/WinIsland.csproj 即可。发布与安装包由 .github/workflows/release.yml 在打 v* 标签时自动完成 (x64 / ARM64 各一份自包含产物 + Inno Setup 安装包)。


插件开发

宿主只管「岛体」——尺寸、圆角、悬停展开、队列排版、点击穿透形状;插件只提供内容。

路线 A:让 AI 帮你做(不会编程也能用)

配套的 AI 技能仓库 → luolangaga/WinLandPluginSkills(MIT) 把「我想给灵动岛做个东西」从零陪跑到上架社区市场:

想点子 → 环境体检 → 从模板建工程 → 写代码(SDK 2.0)
       → 装进你正在用的 WinIsland、你亲手实测 → 打包 .lwp
       → ★先问你同不同意★ → 上传 GitHub / 投稿插件市场

第 1 步 · 安装技能:把下面这段原样发给你的 AI 助手(Claude Code / Command Code / 任何支持 skills 的智能体):

请帮我把这个仓库里的技能装到我的技能目录,装好后告诉我怎么用:
https://github.com/luolangaga/WinLandPluginSkills

不想让 AI 装,也可以手动两行(技能目录:通用 ~/.agents/skills,Claude Code 是 ~/.claude/skills):

git clone --depth 1 https://github.com/luolangaga/WinLandPluginSkills.git "$env:TEMP\WinLandPluginSkills"
Copy-Item -Recurse "$env:TEMP\WinLandPluginSkills\winland-plugin-maker" "$env:USERPROFILE\.agents\skills\"

第 2 步 · 直接说需求(不用提「技能」两个字,AI 会自己认出来):

我想给 WinIsland 灵动岛写一个天气插件,小岛显示当前温度,展开后显示未来三天预报

技能里带齐了这些东西,AI 会自己去读:

技能内文件 作用
SKILL.md 全流程主文档:四条铁律 + 7 步陪跑流程(含话术,用户是新手也能跟上)
references/sdk-api.md SDK 2.0 全部 API、线程模型、csproj 依赖规则,含 1.x 旧写法对照
references/publish.md GitHub 登录、上传源码、投稿市场的逐步命令
references/troubleshooting.md 编译 / 加载 / 动画 / 打包 排错表
assets/plugin-template/ 开箱可编译的插件模板工程(自带 global.json,钉住 .NET 10)
scripts/check-env.ps1、find-winisland.ps1 环境体检、自动定位你安装的 WinIsland

技能里写死了两条硬性规则,防止 AI 越界:必须装进你实际在用的那个 WinIsland、由你亲口确认效果才算测试通过; 任何「发到网上」的动作(建仓库 / push / 开 PR)都必须先问你同意。

路线 B:手写

一个能跑的最小插件(完整文档见 PLUGIN.md):

using WinIsland.Core;

namespace MyPlugin;

public sealed class MyPlugin : IslandPluginBase
{
    protected override Task OnInitializeAsync()
    {
        Log.Info("插件已启动");
        Context.Island.ShowMessage(new IslandMessage { Title = "你好", Text = "来自我的插件" });
        return Task.CompletedTask;
    }

    protected override Task OnShutdownAsync()
    {
        Log.Info("插件已停用");
        return Task.CompletedTask;
    }
}

写完代码,用仓库里的脚本打成插件包(构建输出 + plugin.json → .lwp):

pwsh tools/pack-plugin.ps1 -ProjectDir samples\HelloPlugin

把 .lwp 拖进 plugins/ 目录,或从「设置 → 插件管理 → 安装插件包…」安装:

插件管理

插件管理:安装 / 启停 / 调优先级 / 重新加载 / 看日志,全部即时生效

插件系统 v2 的几条硬规矩

主题 行为
依赖隔离 每个插件跑在可回收的 AssemblyContext 里;WinIsland.Core、System.*/Windows.* 与宿主目录里已有的程序集统一绑定到宿主,其余依赖从插件目录解析(支持插件自带 NuGet 依赖)
热插拔 禁用 → 卸载程序集(用 WeakReference 验证真的被回收)→ 重新启用;更新/删除时先改名移走旧目录,绝不删除正在加载的文件
注册即回收 插件注册的设置页、常驻内容、临时消息、定时器、设置订阅都记在 PluginScope 里,停用时统一撤销——插件自己清理得不干净,宿主兜底
防护 初始化 10 秒超时;单次会话 5 次未处理异常自动停用;所有从宿主进入插件的回调都被包在守卫里(一个插件抛异常不会让整个应用变成 WinUI 的「stowed exception」崩溃)
只读契约 WinIsland.Core 只有接口、数据与特性,没有实现;插件设置自动加上 <插件 id>. 前缀,插件改不到宿主的设置

样例

样例 内容
samples/HelloPlugin 代码构建 UI、私有依赖、设置页、定时器、完整清理
samples/XamlPlugin XAML 视图 + PluginXaml.Load + 逐帧形变动画
samples/HardwareMonitor 真实功能插件:CPU / GPU / 网络 / 帧率,自带 NuGet 依赖

插件市场

「设置 → 插件市场」读取社区仓库 luolangaga/WinLandPlugin 根目录的 index.json:

  • 整个列表只发一次请求,插件图标以 base64 内嵌在清单里(不做逐插件请求)
  • 市场源自动回退:GitHub raw → GitCode 国内镜像 → jsDelivr,客户端记住上次成功的源;也可以用 marketplace.baseUrl 指向自建源
  • 只有点「安装」才会下载 .lwp,且强制校验 SHA-256;README 只在打开「详情」时才取

插件市场

插件详情

详情页能看到版本 / 作者 / 体积 / 许可证 / SHA-256 与插件自带的说明,README 只在打开详情时才取

想投稿?把 plugin.json + <id>.lwp + logo.png(可选)+ README.md(可选)放进 plugins/<id>/ 提 PR, 合并后 Action 会自动重建清单(细节见 PLUGIN.md §9)。


外观与摆放

Apple 灵动岛 Windows Fluent
紧凑态
展开态
  • Apple 灵动岛:不透明纯黑胶囊、大圆角——最接近 iPhone 上的样子
  • Windows Fluent:元素级系统材质(Desktop Acrylic 磨砂玻璃 / Mica 壁纸着色)、1px 描边、小圆角,材质不可用时自动回退纯色

摆放方式有两种,都在「设置 → 通用」里:

  • 屏幕顶部:贴工作区顶部悬浮,队列向下生长
  • 屏幕底部(嵌入任务栏):真的嵌进任务栏条带——自动测量任务栏的空闲段落位(不再假设左边一定是空的)、 跟随任务栏自动隐藏、被别的窗口压住时自动重新置顶;队列向上生长

通用设置页:

通用设置


架构

WinIsland.Core/           插件 SDK(luolan.winland.Core,API v2)——只有接口、数据与特性
WinIsland/                主程序(WinUI 3 / .NET 10 / Windows App SDK)
  Island/                 岛体窗口:状态机、尺寸动画、悬停展开、队列排版、点击穿透形状、摆放策略
  Core/
    Plugins/              插件引擎:发现 / 安装 / 启用 / 热重载 / 卸载,可回收 ALC 与作用域回收
    Marketplace/          插件市场客户端:index.json + ETag 缓存 + 镜像回退 + SHA-256 校验
    SettingsService.cs    设置存储(%LocalAppData%\WinIsland\settings.json)
    Win32.cs              窗口样式、DWM、任务栏条带、topmost 自愈、窗口形状等全部 P/Invoke
  Modules/                内置插件:Media / Battery / Messaging
  Settings/               设置窗口与各页面(通用 / 插件市场 / 插件管理)
samples/                  插件样例:HelloPlugin / XamlPlugin / HardwareMonitor
tools/pack-plugin.ps1     把插件目录打成 .lwp
installer/WinIsland.iss   Inno Setup 安装脚本(每用户安装,无需管理员)

几个值得一提的实现细节:

  • 点击穿透用窗口形状,不用 WM_NCHITTEST:SetWindowRgn 把透明画布裁成岛屿的真实形状(带圆角), 形状之外的像素不属于这个窗口,点击/触摸会直接落到下面的窗口——包括其它进程的窗口。
  • 绝不在展开动画里改窗口大小:改客户区宽度会让 DWM 把上一帧按旧坐标合成进新窗口矩形, 出现一帧「重影」。画布是预留的,展开只动 XAML 内的岛体尺寸。
  • topmost 自愈:任务栏、开始菜单、搜索面板会随时把自己抬到最上层,所以窗口在「任何覆盖自己矩形的可见窗口」之上时 会重新断言置顶;这条逻辑在所有摆放模式下都生效。
  • 一切都可回收:插件卸载后不能留下任何东西——设置页、常驻内容、临时消息、定时器、订阅, 以及(用 WeakReference 验证过的)程序集本身。

常见问题

Q:会挡住全屏游戏吗? 独占全屏 / 全屏优化的游戏、UAC 安全桌面、锁屏界面在 topmost 波段之外,灵动岛不会盖在上面。

Q:为什么展开时队列卡片一样宽、一样高? 这是设计:一列对齐的卡片比参差不齐更好看,所以宿主会统一卡片尺寸,插件视图请用星号/自适应布局, 不要假定自己的声明尺寸就是最终尺寸。

Q:插件能读到我的隐私数据吗? 插件与你自己的程序同样权限运行(不是沙箱),装插件前请看清来源;宿主会在插件出错时保护自身不崩, 但这不等于安全隔离。市场里下载的包在安装前会校验 SHA-256。

Q:日志在哪里? %LocalAppData%\WinIsland\logs\:plugin.host.log 是宿主日志,每个插件另有 plugin.<id>.log。


相关链接

WinUI 3 · .NET 10 · Windows App SDK 2.3 · 插件 API v2

项目介绍

Windows 灵动岛(Dynamic Island)桌面应用 · WinUI 3 / .NET 10 · 支持插件与插件市场

定制我的领域