5.5 KiB
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
{
"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 buildoutput). - Do not ship
LiveWall.Sdk.dll,LiveWall.dll, WPF runtime assemblies, or the .NET runtime — they come from the host. - Native DLLs:
AssemblyLoadContextprobing covers managed assemblies only. UseNativeLibrary.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, currently1.0. This is whatplugin.jsondeclares. It changes only when a contract changes incompatibly. New capabilities are added as new optional interfaces (e.g. a futureIWallpaperSourceProvider), which keeps existing plugins compiling and loading unchanged. - LiveWall host version —
1.8.0today.minHostVersionis compared numerically (1.6.10is newer than1.6.9), so you can safely require a bug fix without pinning a build.
Compatibility check on load, in order:
apiVersionmajor ≠ host API major → Incompatible, with the two versions in the message.minHostVersionnewer than the running host → Incompatible.checksumpresent and different → Rejected (ChecksumMismatch).- Entry/type missing or not implementing
ILiveWallPlugin→ Failed. - Exception in
Initialize→ Failed.
Distributing a plugin
There is no plugin store; distribution is a folder. The simplest safe pattern:
- Ship a zip with exactly the plugin folder inside (
com.example.clock\...). - Publish the SHA-256 of your DLL in the release notes.
- 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
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.