Perluas aplikasi Anda dengan layanan, ekstensi, dan paket

Windows menyediakan beberapa teknologi yang memungkinkan aplikasi Anda menyediakan fungsionalitas ke aplikasi lain atau menggunakan add-in pihak ketiga. Artikel ini membandingkan opsi ekstensibilitas yang tersedia untuk aplikasi desktop SDK Aplikasi Windows.

Gambaran umum opsi ekstensibilitas

Teknologi Deskripsi Identitas paket diperlukan Sistem Operasi Minimum
Layanan aplikasi Komunikasi permintaan/respons antar aplikasi melalui AppServiceConnection Yes Windows 10 1607
Ekstensi aplikasi Model plug-in — aplikasi host menemukan konten dari paket ekstensi Yes Windows 10 1607
Ekstensi paket Ekstensibilitas tingkat paket yang lebih luas dengan uap17:PackageExtension Yes Windows 11
Paket opsional Paket konten tambahan yang melengkapi aplikasi utama Yes Windows 10 1709
Paket sumber daya Aset bahasa, skala, dan aksesibilitas yang dipisahkan berdasarkan pasar Yes Windows 10

Memilih teknologi yang tepat

Gunakan layanan aplikasi saat

  • Anda memerlukan komunikasi dua arah antara aplikasi terpisah.
  • Aplikasi konsumen mengirimkan permintaan dan menunggu respons.
  • Anda ingin mengekspos antarmuka seperti API ke aplikasi lain.

Contoh: Layanan terjemahan yang dapat dipanggil aplikasi lain untuk menerjemahkan teks.

Gunakan ekstensi aplikasi saat

  • Aplikasi Anda memerlukan model plug-in di mana pihak ketiga menyediakan konten, tema, atau add-in.
  • Ekstensi ditemukan pada runtime dari paket yang diinstal.
  • Ekstensi menyediakan data atau konfigurasi, bukan kode yang dapat dieksekusi (eksekusi kode harus menggunakan layanan aplikasi).

Contoh: Editor gambar yang menemukan paket filter dari paket ekstensi yang diinstal.

Gunakan ekstensi paket saat

  • Anda memerlukan ekstensibilitas tingkat paket yang lebih luas pada Windows 11.
  • Ekstensi memerlukan akses ke lebih banyak konten paket daripada yang dimungkinkan oleh model PublicFolder.

Gunakan paket opsional saat

  • Anda memiliki konten tambahan (DLC, fitur premium) yang didistribusikan sebagai paket terpisah.
  • Konten ditulis oleh penerbit yang sama.

Pola arsitektur

Layanan aplikasi dengan pendeteksian ekstensi

Gabungkan ekstensi aplikasi dengan layanan aplikasi untuk arsitektur plug-in lengkap:

  1. Aplikasi host Anda menggunakan AppExtensionCatalog untuk menemukan ekstensi yang diinstal.
  2. Setiap ekstensi mendeklarasikan properti yang menjelaskan kemampuannya.
  3. Saat pengguna mengaktifkan ekstensi, aplikasi host terhubung ke layanan aplikasi ekstensi untuk komunikasi dua arah.
┌─────────────────┐      ┌──────────────────┐
│   Host app       │      │  Extension app    │
│                  │      │                   │
│ AppExtension     │◄────►│ AppExtension      │
│   Catalog        │      │   declaration     │
│                  │      │                   │
│ AppService       │◄────►│ AppService        │
│   Connection     │      │   provider        │
└─────────────────┘      └──────────────────┘

Perluasan konten saja

Untuk skenario yang lebih sederhana di mana ekstensi menyediakan konten statis (tema, templat, file data):

  1. Aplikasi host menemukan ekstensi melalui AppExtensionCatalog.
  2. Ini membaca file dari ekstensi PublicFolder.
  3. Tidak diperlukan layanan aplikasi.

Perbedaan dari ekstensibilitas UWP

Teknologi ekstensibilitas yang dijelaskan di sini berfungsi dengan cara yang sama dalam SDK Aplikasi Windows aplikasi desktop seperti yang mereka lakukan di UWP, dengan satu persyaratan: identitas paket MSIX. Semua fitur ekstensibilitas mengandalkan manifes paket untuk deklarasi dan katalog paket untuk penemuan.

Jika aplikasi desktop Anda tidak dikemas, Anda tidak dapat menggunakan teknologi ekstensibilitas ini. Pertimbangkan pendekatan alternatif seperti:

  • Antarmuka plug-in berbasis COM
  • Penemuan ekstensi berbasis sistem file
  • Pipa bernama atau mekanisme IPC lainnya

Penemuan plugin berbasis file untuk aplikasi yang tidak dikemas

Untuk aplikasi WinUI 3 yang tidak dikemas, Anda dapat menerapkan sistem plugin menggunakan .NET AssemblyLoadContext untuk memuat ekstensi dari folder yang diketahui:

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

Memuat rakitan dari disk tanpa validasi adalah risiko keamanan. Dalam produksi, verifikasi tanda tangan rakitan (seperti Authenticode) sebelum memuat, batasi izin ACL direktori plugin, dan pertimbangkan untuk menjalankan plugin dalam proses terpisah dengan hak istimewa yang dikurangi.

Definisikan sebuah kontrak antarmuka bersama dalam assembly terpisah yang direferensikan oleh host dan plugin:

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

Note

Menggunakan isCollectible: true dalam AssemblyLoadContext memungkinkan Anda untuk membongkar plugin pada runtime. Pendekatan ini menghindari masalah pembuatan versi yang dapat ditimbulkan oleh MEF (Managed Extensibility Framework) pada aplikasi desktop.