initial commit

This commit is contained in:
2026-11-04 14:29:22 -06:00
parent 73028cc5ba
commit 3f37abf34a
170 changed files with 22100 additions and 0 deletions
+123
View File
@@ -0,0 +1,123 @@
# Packaging, versioning and distribution
## Folder layout
```
%APPDATA%\LiveWall\plugins\
└── com.example.clock\ ← folder name is free-form; the id comes from plugin.json
├── plugin.json ← required
├── ClockOverlayPlugin.dll ← the entry assembly ("entry")
├── Newtonsoft.Json.dll ← optional private dependencies
└── assets\... ← optional data
```
`%APPDATA%\LiveWall\plugin-data\<id>\` is yours to write to at run time (`IPluginStorage`).
The plugin folder is opened by **Plugins ▸ Open plugin folder**; a starter manifest is written by
**Create plugin template** (into `plugins\com.example.myplugin\`).
## `plugin.json`
```json
{
"id": "com.example.clock",
"name": "Desktop Clock",
"version": "1.0.0",
"author": "You",
"description": "A clock on the wallpaper.",
"homepage": "https://example.com/clock",
"apiVersion": "1.0",
"entry": "ClockOverlayPlugin.dll",
"type": "ClockOverlayPlugin.ClockPlugin",
"minHostVersion": "1.8.0",
"permissions": ["DesktopOverlay", "SettingsUi", "Commands"],
"checksum": "",
"loadPriority": 0
}
```
| Field | Required | Notes |
|---|---|---|
| `id` | yes | Reverse-DNS-ish, unique, stable. Used for data folder, trust store and log prefix. No `\ / : * ? " < > \|`. |
| `name` | yes | Shown in the UI. Falls back to the folder name. |
| `version` | yes | Informational (`1.2.3`). |
| `author` | recommended | Shown in the warning dialog. |
| `description` | recommended | One sentence. |
| `homepage` | no | Where the user can see the code. |
| `apiVersion` | yes | Must be `"1.0"` for this SDK. Major must match; `1`, `1.0`, `1.0.0` are accepted. |
| `entry` | yes | File name (or relative path) of the assembly inside the plugin folder. |
| `type` | yes | Full name of the public class implementing `ILiveWallPlugin`. |
| `minHostVersion` | recommended | Refuses to load on older LiveWall instead of failing at `TypeLoadException`. |
| `permissions` | yes (may be empty) | Array of `PluginPermission` names, or a single flag string. Unknown names are listed in the warning dialog as "asks for things this LiveWall does not know". |
| `checksum` | optional | SHA-256 (hex, case-insensitive) of the entry assembly. When set, a mismatch rejects the plugin. |
| `loadPriority` | optional | Higher loads earlier (default `0`). Use it when plugin B expects plugin A's event to already be published. |
Manifest mistakes are reported in the row (`Invalid manifest: …`) and in the log — nothing is
guessed.
## What can live in the folder
Everything in the plugin folder is added as a private assembly-probing path, so your own dependencies
are found without touching LiveWall's:
* Private libraries: copy them next to your DLL (normal `dotnet build` output).
* **Do not** ship `LiveWall.Sdk.dll`, `LiveWall.dll`, WPF runtime assemblies, or the .NET runtime —
they come from the host.
* Native DLLs: `AssemblyLoadContext` probing covers managed assemblies only. Use
`NativeLibrary.Load(context.Storage.PathFor("your.dll"))` with a copy in your data folder if you
need one.
* WPF controls with XAML resources: pack URIs of a referenced library work; XAML inside your own
assembly works (`/YourAssembly;component/...`).
## Versioning
Two independent numbers:
* **LiveWall plugin API** — `PluginApi.Version`, currently `1.0`. This is what `plugin.json` declares.
It changes only when a contract changes incompatibly. New capabilities are added as *new optional
interfaces* (e.g. a future `IWallpaperSourceProvider`), which keeps existing plugins compiling and
loading unchanged.
* **LiveWall host version** — `1.8.0` today. `minHostVersion` is compared numerically (`1.6.10` is
newer than `1.6.9`), so you can safely require a bug fix without pinning a build.
Compatibility check on load, in order:
1. `apiVersion` major ≠ host API major → **Incompatible**, with the two versions in the message.
2. `minHostVersion` newer than the running host → **Incompatible**.
3. `checksum` present and different → **Rejected** (`ChecksumMismatch`).
4. Entry/type missing or not implementing `ILiveWallPlugin` → **Failed**.
5. Exception in `Initialize` → **Failed**.
## Distributing a plugin
There is no plugin store; distribution is a folder. The simplest safe pattern:
1. Ship a zip with exactly the plugin folder inside (`com.example.clock\...`).
2. Publish the SHA-256 of your DLL in the release notes.
3. Tell users: unpack into `%APPDATA%\LiveWall\plugins\`, then **Plugins ▸ Rescan ▸ Enable**, and
compare the hash the warning dialog shows against your published one.
Putting the same value in `plugin.json`'s `checksum` makes the app verify it automatically and turns
a corrupt download into a clear error instead of a mysterious load failure.
### Updating a plugin
Replace the files, press **Rescan**. The old load context is unloaded first. Because the DLL has
changed, the plugin becomes unverified and the user must approve the new hash — this is deliberate
and cannot be bypassed by the plugin itself.
### Uninstalling
**Disable** the plugin, delete its folder, and optionally delete `%APPDATA%\LiveWall\plugin-data\<id>`.
## Building the sample
```bash
cd samples/ClockOverlayPlugin
dotnet build -c Release
# bin/Release/net8.0-windows/{ClockOverlayPlugin.dll, plugin.json}
```
The sample's csproj sets `<Private>false</Private>` on the SDK reference and
`CopyLocalLockFileAssemblies=false`, so its output contains only the plugin assembly — exactly what
you want to copy into the plugins folder.