Erweitern der App mit Diensten, Erweiterungen und Paketen

Windows bietet mehrere Technologien, mit denen Ihre App Funktionen für andere Apps bereitstellen oder Add-Ins von Drittanbietern nutzen kann. In diesem Artikel werden die verfügbaren Erweiterbarkeitsoptionen für Windows App SDK Desktop-Apps verglichen.

Übersicht über Erweiterbarkeitsoptionen

Technologie Description Paketidentität erforderlich Mindestbetriebssystem
App-Dienste Anforderungs-/Antwortkommunikation zwischen Apps über AppServiceConnection Yes Windows 10 1607
App-Erweiterungen Plug-In-Modell – Host-App ermittelt Inhalte aus Erweiterungspaketen Yes Windows 10 1607
Paketerweiterungen Umfassendere Erweiterung auf Paketebene mit uap17:PackageExtension Yes Windows 11
Optionale Pakete Zusätzliche Inhaltspakete, die eine Haupt-App ergänzen Yes Windows 10 1709
Ressourcenpakete Vom Markt getrennte Sprach-, Skalierungs- und Barrierefreiheitsressourcen Yes Windows 10

Auswählen der richtigen Technologie

Verwenden Sie App-Dienste, wenn

  • Sie benötigen bidirektionale Kommunikation zwischen separaten Apps.
  • Die Consumer-App sendet eine Anforderung und wartet auf eine Antwort.
  • Sie möchten eine API-ähnliche Schnittstelle für andere Apps verfügbar machen.

Beispiel: Ein Übersetzungsdienst, den andere Apps aufrufen können, um Text zu übersetzen.

Verwenden Sie App-Erweiterungen, wenn

  • Ihre App benötigt ein Plug-In-Modell, bei dem Drittanbieter Inhalte, Designs oder Add-Ins bereitstellen.
  • Erweiterungen werden zur Laufzeit aus installierten Paketen ermittelt.
  • Erweiterungen stellen Daten oder Konfiguration bereit, nicht ausführbaren Code (Codeausführung sollte App-Dienste verwenden).

Beispiel: Ein Bild-Editor, der Filterpakete aus installierten Erweiterungspaketen ermittelt.

Verwenden Sie Paketerweiterungen, wenn

  • Sie benötigen eine umfassendere Erweiterbarkeit auf Paketebene für Windows 11.
  • Erweiterungen benötigen Zugriff auf mehr Paketinhalte, als das PublicFolder Modell zulässt.

Optionale Pakete verwenden, wenn

  • Sie haben zusätzliche Inhalte (DLC, Premium-Features) als separate Pakete verteilt.
  • Der Inhalt wird vomselben Herausgeber erstellt.

Architekturmuster

App-Service mit Erweiterungserkennung

Kombinieren Sie App-Erweiterungen mit App-Diensten für eine vollständige Plug-In-Architektur:

  1. Ihre Host-App verwendet AppExtensionCatalog , um installierte Erweiterungen zu ermitteln.
  2. Jede Erweiterung deklariert Eigenschaften, die ihre Funktionen beschreiben.
  3. Wenn der Benutzer eine Erweiterung aktiviert, stellt die Host-App für die bidirektionale Kommunikation eine Verbindung mit dem App-Dienst der Erweiterung bereit.
┌─────────────────┐      ┌──────────────────┐
│   Host app       │      │  Extension app    │
│                  │      │                   │
│ AppExtension     │◄────►│ AppExtension      │
│   Catalog        │      │   declaration     │
│                  │      │                   │
│ AppService       │◄────►│ AppService        │
│   Connection     │      │   provider        │
└─────────────────┘      └──────────────────┘

Nur Inhaltserweiterung

Für einfachere Szenarien, in denen Erweiterungen statische Inhalte bereitstellen (Designs, Vorlagen, Datendateien):

  1. Die Host-App ermittelt Erweiterungen über AppExtensionCatalog.
  2. Es liest Dateien aus dem PublicFolder der Erweiterung.
  3. Es ist kein App-Dienst erforderlich.

Unterschiede gegenüber der UWP-Erweiterbarkeit

Die hier beschriebenen Erweiterbarkeitstechnologien funktionieren in Windows App SDK Desktop-Apps genauso wie in UWP, mit einer Anforderung: MSIX-Paketidentität. Alle Erweiterbarkeitsfeatures basieren auf dem Paketmanifest für Deklarationen und den Paketkatalog für die Ermittlung.

Wenn Ihre Desktop-App entpackt ist, können Sie diese Erweiterbarkeitstechnologien nicht verwenden. Ziehen Sie alternative Ansätze in Betracht, z. B.:

  • COM-basierte Plug-In-Schnittstellen
  • Dateisystembasierte Erweiterungsermittlung
  • Benannte Rohre oder andere IPC-Mechanismen

Dateibasierte Plug-In-Ermittlung für entpackte Apps

Für entpackte WinUI 3-Apps können Sie ein Plug-In-System mithilfe von .NET AssemblyLoadContext implementieren, um Erweiterungen aus einem bekannten Ordner zu laden:

public class PluginLoader
{
    private readonly string _pluginDirectory;

    public PluginLoader(string pluginDirectory)
    {
        _pluginDirectory = pluginDirectory;
    }

    public IEnumerable<T> LoadPlugins<T>() where T : class
    {
        if (!Directory.Exists(_pluginDirectory))
            yield break;

        foreach (var dll in Directory.GetFiles(_pluginDirectory, "*.dll"))
        {
            var context = new PluginLoadContext(dll);
            var assembly = context.LoadFromAssemblyPath(Path.GetFullPath(dll));

            foreach (var type in assembly.GetTypes()
                .Where(t => typeof(T).IsAssignableFrom(t) && !t.IsAbstract))
            {
                if (Activator.CreateInstance(type) is T plugin)
                    yield return plugin;
            }
        }
    }
}

// Custom AssemblyLoadContext to isolate plugin dependencies
public class PluginLoadContext : AssemblyLoadContext
{
    private readonly AssemblyDependencyResolver _resolver;

    public PluginLoadContext(string pluginPath) : base(isCollectible: true)
    {
        _resolver = new AssemblyDependencyResolver(pluginPath);
    }

    protected override Assembly? Load(AssemblyName assemblyName)
    {
        var path = _resolver.ResolveAssemblyToPath(assemblyName);
        return path != null ? LoadFromAssemblyPath(path) : null;
    }
}

Warning

Das Laden von Assemblys vom Datenträger ohne Überprüfung ist ein Sicherheitsrisiko. Überprüfen Sie in der Produktion Assemblysignaturen (z. B. Authenticode) vor dem Laden, beschränken Sie die ACL-Berechtigungen des Plug-In-Verzeichnisses, und erwägen Sie, Plug-Ins in einem separaten Prozess mit reduzierten Berechtigungen auszuführen.

Definieren Sie einen gemeinsamen Schnittstellenvertrag in einer separaten Assembly, auf die sowohl der Host als auch die Plugins verweisen:

// Contoso.App.Contracts (shared assembly)
public interface IPluginExtension
{
    string Name { get; }
    string Description { get; }
    void Execute(IServiceProvider services);
}

Note

Die Verwendung von isCollectible: true in AssemblyLoadContext ermöglicht es Ihnen, Plug-Ins zur Laufzeit zu entladen. Dieser Ansatz vermeidet die Versionsprobleme, die MEF (Managed Extensibility Framework) in Desktopanwendungen verursachen kann.