This toolkit comes with several MSBuild tasks to automate common (and annoying) tasks while building your plugin. The sample project csproj has a fully functional MSBuild pipeline that utilizes all of these tasks to automate as much tedium as possible. These work on both Windows and MacOS.
- CloseStreamDeck: A before-
BeforeBuildtask that closes your open Stream Deck software. - GenerateManifest: An after-
Buildtask that uses the manifest source generators to automatically build your plugin'smanifest.json. See the Manifest Generation page of the wiki for more details. - RenameOutputDirectory: An after-
Buildtask to rename your build directory to the format the Stream Deck expects. By default in the example project, the directory uses the<AssemblyName>MSBuild property in lower case. - LinkPlugin: An after-
Buildtask that uses the Stream Deck CLI to link your build directory (for both Debug and Release builds) to the Stream Deck plugin directory. - OpenStreamDeck: An after-
Buildtask to reopen the Stream Deck software when the build is complete. When using JetBrains Rider, the build might occasionally fail witherror MSB3027: Could not copy.... If this happens, run./kill-msbuild.ps1from the repository's root directory and rebuild. Running thedotnet buildanddotnet publishcommands directly shouldn't produce this error unless you first ran the build through Rider. - ExtractSdpiHtml: An after-
CoreCompiletask that works in conjunction with theSdpiGeneratorsource generator to create property inspector HTML and JavaScript files for your plugins. See the SdpiGenerator documentation in the wiki for more details.
flowchart TD
BT["BuildTasks (InitialTargets)\nBuilds the BuildTasks assembly"]
CS["CloseStreamDeck\nKills the Stream Deck process"]
COMPILE["CoreCompile\nCompile managed IL"]
EH["WriteSdpiHtmlOutput\nExtract SDPI HTML/JS via ExtractSdpiHtml task"]
BUILD["Build complete\nOutput: bin/Config/AnyCPU/name.sdPlugin/"]
GM["GenerateManifest\nReflect on managed DLL → manifest.json"]
BT --> CS --> COMPILE
COMPILE -.->|AfterTargets: CoreCompile| EH
COMPILE --> BUILD
BUILD -->|AfterTargets: Build| GM
GM -->|"dotnet build -c Debug"| LINK
GM -->|"dotnet publish -c Release"| NAOT
subgraph dbg ["Debug"]
LINK["LinkPlugin\nstreamdeck link {buildDir}"]
OSD_D["OpenStreamDeck"]
LINK --> OSD_D
end
subgraph rel ["Release"]
NAOT["NativeAOT Publish\nOutput: bin/Release/win-x64/publish/"]
COPY["Copy manifest.json\nAnyCPU/name.sdPlugin/ → publish/"]
DEL["Delete native PDB"]
REN["RenameOutputDirectory\npublish/ → win-x64/name.sdPlugin/"]
PACK["PackagePlugin\nstreamdeck pack {buildDir} -o {outputDir}"]
OSD_R["OpenStreamDeck"]
NAOT -->|AfterTargets: Publish| COPY --> DEL --> REN --> PACK --> OSD_R
end
The build tasks will create a symbolic link to your debug built directory in the Stream Deck plugin directory. If the link already exists, you'll see a warning.
The plugin directories are:
MacOS: ~/Library/Application Support/Elgato/StreamDeck/Plugins/
Windows: %APPDATA%\Elgato\StreamDeck\Plugins\
Behaves similarly to the Debug build, but with a few extra steps to handle the differences in the output of a Native AOT publish.
The tasks will copy the generated manifest.json from the AnyCPU build output to the publish directory, delete the native PDB
generated by Native AOT, and rename the publish output directory to match the expected format for Stream Deck plugins.
Behaves identically to Release but packages the plugin using the Stream Deck CLI and places the resulting .streamDeckPlugin
file in an output directory in your project root.