Tutorial: Mengirim pemberitahuan push ke aplikasi Xamarin.Forms menggunakan Azure Notification Hubs melalui layanan backend

Unduh Sampel Mengunduh sampel

Dalam tutorial ini, Anda menggunakan Azure Notification Hubs untuk mendorong pemberitahuan ke aplikasi Xamarin.Forms yang menargetkan Android dan iOS.

Backend ASP.NET Core Web API digunakan untuk menangani pendaftaran perangkat untuk klien menggunakan pendekatan Penginstalan terbaru dan terbaik. Layanan ini juga akan mengirim pemberitahuan push secara lintas platform.

Operasi ini ditangani menggunakan Notification Hubs SDK untuk operasi backend. Detail lebih lanjut tentang pendekatan keseluruhan disediakan dalam dokumentasi Mendaftar dari backend aplikasi Anda .

Tutorial ini membawa Anda melalui langkah-langkah berikut:

Prasyarat

Untuk mengikutinya, Anda memerlukan:

  • Langganan Azure tempat Anda dapat membuat dan mengelola sumber daya.
  • Mac dengan Visual Studio untuk Mac terinstal atau PC yang menjalankan Visual Studio 2019.
  • Pengguna Visual Studio 2019 juga harus menginstal pengembangan Seluler dengan beban kerja .NET dan ASP.NET serta pengembangan web .
  • Kemampuan untuk menjalankan aplikasi di Android (perangkat fisik atau emulator) atau iOS (hanya perangkat fisik).

Untuk Android, Anda harus memiliki:

  • Developer membuka kunci perangkat fisik atau emulator (menjalankan API 26 ke atas dengan Google Play Services terinstal).

Untuk iOS, Anda harus memiliki:

Catatan

Simulator iOS tidak mendukung pemberitahuan jarak jauh sehingga perangkat fisik diperlukan saat menjelajahi sampel ini di iOS. Namun, Anda tidak perlu menjalankan aplikasi di Android dan iOS untuk menyelesaikan tutorial ini.

Anda dapat mengikuti langkah-langkah dalam contoh prinsip pertama ini tanpa pengalaman sebelumnya. Namun, Anda akan mendapat manfaat dari memiliki keakraban dengan aspek-aspek berikut.

Penting

Langkah-langkah yang disediakan khusus untuk Visual Studio untuk Mac. Dimungkinkan untuk mengikuti menggunakan Visual Studio 2019 tetapi mungkin ada beberapa perbedaan untuk direkonsiliasi. Misalnya, deskripsi antarmuka pengguna dan alur kerja, nama templat, konfigurasi lingkungan, dan sebagainya.

Menyiapkan Push Notification Services dan Azure Notification Hub

Di bagian ini, Anda menyiapkan Firebase Cloud Messaging (FCM) dan Apple Push Notification Services (APNS). Anda kemudian membuat dan mengonfigurasi hub pemberitahuan untuk bekerja dengan layanan tersebut.

Membuat proyek Firebase dan mengaktifkan Firebase Cloud Messaging untuk Android

  1. Masuk ke konsol Firebase. Buat proyek Firebase baru yang memasukkan PushDemo sebagai Nama proyek.

    Catatan

    Nama unik akan dibuat untuk Anda. Secara default ini terdiri dari varian huruf kecil dari nama yang Anda berikan ditambah angka yang dihasilkan yang dipisahkan oleh tanda hubung. Anda dapat mengubah ini jika Anda ingin asalkan masih unik secara global.

  2. Setelah membuat proyek, pilih Tambahkan Firebase ke aplikasi Android Anda.

    Menambahkan Firebase ke aplikasi Android Anda

  3. Pada halaman Tambahkan Firebase ke aplikasi Android Anda , lakukan langkah-langkah berikut.

    1. Untuk nama paket Android, masukkan nama untuk paket Anda. Misalnya: com.<organization_identifier>.<package_name>.

      Tentukan nama paket

    2. Pilih Daftarkan aplikasi.

    3. Pilih Unduh google-services.json. Kemudian simpan file ke folder lokal untuk digunakan nanti dan pilih Berikutnya.

      Unduh google-services.json

    4. Pilih Berikutnya.

    5. Pilih Lanjutkan ke konsol

      Catatan

      Jika tombol Lanjutkan ke konsol tidak diaktifkan, karena pemeriksaan verifikasi penginstalan , maka pilih Lewati langkah ini.

  4. Di konsol Firebase, pilih roda gigi untuk proyek Anda. Lalu pilih Pengaturan Proyek.

    Pilih Pengaturan Proyek

    Catatan

    Jika Anda belum mengunduh file google-services.json , Anda dapat mengunduhnya di halaman ini.

  5. Beralih ke tab Pesan Cloud di bagian atas. Salin dan simpan kunci Server untuk digunakan nanti. Anda menggunakan nilai ini untuk mengonfigurasi hub pemberitahuan Anda.

    Salin kunci server

Mendaftarkan aplikasi iOS Anda untuk pemberitahuan push

Untuk mengirim pemberitahuan push ke app iOS, daftarkan aplikasi Anda dengan Apple, dan daftarkan juga untuk pemberitahuan push.

  1. Jika Anda belum mendaftarkan aplikasi, telusuri ke Portal Provisi iOS di Pusat Pengembang Apple. Masuk ke portal dengan ID Apple Anda, navigasi ke Sertifikat, Pengidentifikasi & Profil, lalu pilih Pengidentifikasi. Klik + untuk mendaftarkan aplikasi baru.

    Halaman ID Aplikasi Portal Provisi iOS

  2. Pada layar Daftarkan Pengidentifikasi Baru , pilih tombol radio ID Aplikasi . Lalu pilih Lanjutkan.

    Portal Provisi iOS mendaftarkan halaman ID baru

  3. Perbarui tiga nilai berikut untuk aplikasi baru Anda, lalu pilih Lanjutkan:

    • Deskripsi: Ketik nama deskriptif untuk aplikasi Anda.

    • ID Bundel: Masukkan ID Bundel formulir com.organization_identifier<>.<>product_name seperti yang disebutkan dalam Panduan Distribusi Aplikasi. Dalam cuplikan layar berikut, mobcat nilai digunakan sebagai pengidentifikasi organisasi dan nilai PushDemo digunakan sebagai nama produk.

      Portal Provisi iOS mendaftarkan halaman ID aplikasi

    • Pemberitahuan Push: Periksa opsi Pemberitahuan Push di bagian Kemampuan .

      Formulir untuk mendaftarkan ID Aplikasi baru

      Tindakan ini menghasilkan ID Aplikasi dan permintaan yang Anda konfirmasi informasinya. Pilih Lanjutkan, lalu pilih Daftar untuk mengonfirmasi ID Aplikasi baru.

      Mengonfirmasi ID Aplikasi baru

      Setelah memilih Daftar, Anda akan melihat ID Aplikasi baru sebagai item baris di halaman Sertifikat, Pengidentifikasi, & Profil .

  4. Di halaman Sertifikat, Pengidentifikasi & Profil , di bawah Pengidentifikasi, temukan item baris ID Aplikasi yang Anda buat. Kemudian, pilih barisnya untuk menampilkan layar Edit Konfigurasi ID Aplikasi Anda .

Membuat sertifikat untuk Notification Hubs

Sertifikat diperlukan untuk mengaktifkan hub pemberitahuan agar berfungsi dengan Apple Push Notification Services (APNS) dan dapat disediakan dengan salah satu dari dua cara:

  1. Membuat sertifikat push p12 yang dapat diunggah langsung ke Notification Hub (pendekatan asli)

  2. Membuat sertifikat p8 yang dapat digunakan untuk autentikasi berbasis token (pendekatan yang lebih baru dan direkomendasikan)

Pendekatan yang lebih baru memiliki sejumlah manfaat seperti yang didokumentasikan dalam autentikasi berbasis Token (HTTP/2) untuk APNS. Langkah-langkah yang lebih sedikit diperlukan tetapi juga diamanatkan untuk skenario tertentu. Namun, langkah-langkah telah disediakan untuk kedua pendekatan karena keduanya akan berfungsi untuk tujuan tutorial ini.

OPSI 1: Membuat sertifikat push p12 yang dapat diunggah langsung ke Notification Hub
  1. Di Mac Anda, jalankan alat Akses Rantai Kunci. Ini dapat dibuka dari folder Utilitas atau folder Lainnya di Launchpad.

  2. Pilih Akses Rantai Kunci, perluas Asisten Sertifikat, lalu pilih Minta Sertifikat dari Otoritas Sertifikat.

    Menggunakan Akses Rantai Kunci untuk meminta sertifikat baru

    Catatan

    Secara default, Akses Rantai Kunci memilih item pertama dalam daftar. Ini bisa menjadi masalah jika Anda berada dalam kategori Sertifikat dan Otoritas Sertifikasi Hubungan Pengembang Di Seluruh Dunia Apple bukan item pertama dalam daftar. Pastikan Anda memiliki item non-kunci, atau kunci Otoritas Sertifikasi Hubungan Pengembang Di Seluruh Dunia Apple dipilih, sebelum membuat CSR (Permintaan Penandatanganan Sertifikat).

  3. Pilih Alamat Email Pengguna Anda, masukkan nilai Nama Umum Anda, pastikan Anda menentukan Disimpan ke disk, lalu pilih Lanjutkan. Biarkan ALAMAT Email CA kosong karena tidak diperlukan.

    Informasi sertifikat yang diharapkan

  4. Masukkan nama untuk file Permintaan Penandatanganan Sertifikat (CSR) di Simpan Sebagai, pilih lokasi di Tempat, lalu pilih Simpan.

    Pilih nama file untuk sertifikat

    Tindakan ini menyimpan file CSR di lokasi yang dipilih. Lokasi defaultnya adalah Desktop. Ingat lokasi yang dipilih untuk file.

  5. Kembali ke halaman Sertifikat, Pengidentifikasi & Profil di Portal Provisi iOS, gulir ke bawah ke opsi Pemberitahuan Push yang dicentang, lalu pilih Konfigurasikan untuk membuat sertifikat.

    Edit halaman ID Aplikasi

  6. Jendela Sertifikat TLS/SSL layanan Pemberitahuan Push Apple muncul. Pilih tombol Buat Sertifikat di bawah bagian Pengembangan Sertifikat TLS/SSL .

    Tombol Buat sertifikat untuk ID Aplikasi

    Layar Buat Sertifikat baru ditampilkan.

    Catatan

    Tutorial ini menggunakan sertifikat pengembangan. Proses yang sama digunakan saat mendaftarkan sertifikat produksi. Pastikan Anda menggunakan jenis sertifikat yang sama saat mengirim pemberitahuan.

  7. Pilih Pilih File, telusuri ke lokasi tempat Anda menyimpan file CSR, lalu klik dua kali nama sertifikat untuk memuatnya. Lalu pilih Lanjutkan.

  8. Setelah portal membuat sertifikat, pilih tombol Unduh . Simpan sertifikat, dan ingat lokasi penyimpanannya.

    Halaman unduhan sertifikat yang dihasilkan

    Sertifikat diunduh dan disimpan ke komputer Anda di folder Unduhan Anda.

    Menemukan file sertifikat di folder Unduhan

    Catatan

    Secara default, sertifikat pengembangan yang diunduh diberi nama aps_development.cer.

  9. Klik dua kali aps_development.cer sertifikat push yang diunduh. Tindakan ini menginstal sertifikat baru di Rantai Kunci, seperti yang ditunjukkan pada gambar berikut:

    Daftar sertifikat akses rantai kunci memperlihatkan sertifikat baru

    Catatan

    Meskipun nama dalam sertifikat Anda mungkin berbeda, nama tersebut akan diawali dengan Layanan Pendorongan iOS Pengembangan Apple dan memiliki pengidentifikasi bundel yang sesuai yang terkait dengannya.

  10. Di Akses Rantai Kunci, Klik Kontrol + pada sertifikat push baru yang Anda buat di kategori Sertifikat. Pilih Ekspor, beri nama file, pilih format p12 , lalu pilih Simpan.

    Mengekspor sertifikat sebagai format p12

    Anda dapat memilih untuk melindungi sertifikat dengan kata sandi, tetapi kata sandi bersifat opsional. Klik OK jika Anda ingin melewati pembuatan kata sandi. Catat nama file dan lokasi sertifikat p12 yang diekspor. Mereka digunakan untuk mengaktifkan autentikasi dengan APN.

    Catatan

    Nama dan lokasi file p12 Anda mungkin berbeda dari apa yang digambarkan dalam tutorial ini.

OPSI 2: Membuat sertifikat p8 yang dapat digunakan untuk autentikasi berbasis token
  1. Catat detail berikut:

    • Awalan ID Aplikasi (ID Tim)
    • ID Bundel
  2. Kembali ke Sertifikat, Pengidentifikasi & Profil, klik Kunci.

    Catatan

    Jika Anda sudah memiliki kunci yang dikonfigurasi untuk APNS, Anda dapat menggunakan kembali sertifikat p8 yang Anda unduh tepat setelah dibuat. Jika demikian, Anda dapat mengabaikan langkah 3 hingga 5.

  3. Klik tombol + (atau tombol Buat kunci ) untuk membuat kunci baru.

  4. Berikan nilai Nama Kunci yang sesuai, lalu centang opsi Layanan Pemberitahuan Push Apple (APNS), lalu klik Lanjutkan, diikuti dengan Daftar di layar berikutnya.

  5. Klik Unduh lalu pindahkan file p8 (diawali dengan AuthKey_) ke direktori lokal yang aman, lalu klik Selesai.

    Catatan

    Pastikan untuk menyimpan file p8 Anda di tempat yang aman (dan simpan cadangan). Setelah mengunduh kunci Anda, kunci tidak dapat diunduh ulang karena salinan server dihapus.

  6. Pada Kunci, klik kunci yang Anda buat (atau kunci yang ada jika Anda telah memilih untuk menggunakannya sebagai gantinya).

  7. Catat nilai ID Kunci .

  8. Buka sertifikat p8 Anda dalam aplikasi pilihan Anda yang sesuai seperti Visual Studio Code. Catat nilai kunci (antara -----BEGIN PRIVATE KEY----- dan -----END PRIVATE KEY-----).

    KUNCI PRIVAT -----BEGIN-----
    <key_value>
    -----END KUNCI PRIVAT-----

    Catatan

    Ini adalah nilai token yang akan digunakan nanti untuk mengonfigurasi Notification Hub.

Di akhir langkah-langkah ini, Anda harus memiliki informasi berikut untuk digunakan nanti di Mengonfigurasi hub pemberitahuan Anda dengan informasi APNS:

  • ID Tim (lihat langkah 1)
  • ID Bundel (lihat langkah 1)
  • ID Kunci (lihat langkah 7)
  • Nilai token (nilai kunci p8 yang diperoleh pada langkah 8)

Membuat profil provisi untuk aplikasi

  1. Kembali ke Portal Provisi iOS, pilih Sertifikat, Pengidentifikasi & Profil, pilih Profil dari menu sebelah kiri, lalu pilih + untuk membuat profil baru. Layar Daftarkan Profil Provisi Baru muncul.

  2. Pilih Pengembangan Aplikasi iOS di bagian Pengembangan sebagai jenis profil provisi, lalu pilih Lanjutkan.

    Daftar profil provisi

  3. Selanjutnya, pilih ID aplikasi yang Anda buat dari daftar drop-down ID Aplikasi , dan pilih Lanjutkan.

    Pilih ID Aplikasi

  4. Di jendela Pilih sertifikat , pilih sertifikat pengembangan yang Anda gunakan untuk penandatanganan kode, dan pilih Lanjutkan.

    Catatan

    Sertifikat ini bukan sertifikat push yang Anda buat di langkah sebelumnya. Ini adalah sertifikat pengembangan Anda. Jika tidak ada, Anda harus membuatnya karena ini adalah prasyarat untuk tutorial ini. Sertifikat pengembang dapat dibuat di Portal Pengembang Apple, melalui Xcode atau di Visual Studio.

  5. Kembali ke halaman Sertifikat, Pengidentifikasi & Profil , pilih Profil dari menu sebelah kiri, lalu pilih + untuk membuat profil baru. Layar Daftarkan Profil Provisi Baru muncul.

  6. Di jendela Pilih sertifikat , pilih sertifikat pengembangan yang Anda buat. Lalu pilih Lanjutkan.

  7. Selanjutnya, pilih perangkat yang akan digunakan untuk pengujian, dan pilih Lanjutkan.

  8. Terakhir, pilih nama untuk profil di Nama Profil Provisi, dan pilih Buat.

    Pilih nama profil provisi

  9. Saat profil provisi baru dibuat, pilih Unduh. Ingat lokasi penyimpanannya.

  10. Telusuri ke lokasi profil provisi, lalu klik dua kali untuk menginstalnya di komputer pengembangan Anda.

Membuat Notification Hub

Di bagian ini, Anda membuat hub pemberitahuan dan mengonfigurasi autentikasi dengan APNS. Anda dapat menggunakan sertifikat push p12 atau autentikasi berbasis token. Jika Anda ingin menggunakan hub pemberitahuan yang telah Anda buat, Anda dapat melompat ke langkah 5.

  1. Masuk ke Azure.

  2. Klik Buat sumber daya, lalu cari dan pilih Notification Hub, lalu klik Buat.

  3. Perbarui bidang berikut, lalu klik Buat:

    DETAIL DASAR

    Berlangganan: Pilih Langganan target dari daftar drop-down
    Grup Sumber Daya: Buat Grup Sumber Daya baru (atau pilih yang sudah ada)

    DETAIL NAMESPACE

    Namespace Notification Hub: Masukkan nama unik global untuk namespace Notification Hub

    Catatan

    Pastikan opsi Buat baru dipilih untuk bidang ini.

    DETAIL NOTIFICATION HUB

    Notification Hub: Masukkan nama untuk Notification Hub
    Lokasi: Pilih lokasi yang sesuai dari daftar drop-down
    Tingkat Harga: Pertahankan opsi Gratis default

    Catatan

    Kecuali Anda telah mencapai jumlah maksimum hub pada tingkat gratis.

  4. Setelah Notification Hub disediakan, navigasikan ke sumber daya tersebut.

  5. Navigasikan ke Notification Hub baru Anda.

  6. Pilih Kebijakan Akses dari daftar (di bawah KELOLA) .

  7. Catat nilai Nama Kebijakan bersama dengan nilai String Koneksi terkait.

Mengonfigurasi Notification Hub Anda dengan informasi APNS

Di bawah Layanan Pemberitahuan, pilih Apple lalu ikuti langkah-langkah yang sesuai berdasarkan pendekatan yang Anda pilih sebelumnya di bagian Membuat Sertifikat untuk Notification Hubs .

Catatan

Gunakan Produksi untuk Mode Aplikasi hanya jika Anda ingin mengirim pemberitahuan push kepada pengguna yang membeli aplikasi Anda dari toko.

OPSI 1: Menggunakan sertifikat push .p12

  1. Pilih Sertifikat.

  2. Pilih ikon file.

  3. Pilih file .p12 yang Anda ekspor sebelumnya, lalu pilih Buka.

  4. Jika perlu, tentukan kata sandi yang benar.

  5. Pilih Mode kotak pasir .

  6. Pilih Simpan.

OPSI 2: Menggunakan autentikasi berbasis token

  1. Pilih Token.

  2. Masukkan nilai berikut yang Anda peroleh sebelumnya:

    • ID Kunci
    • ID Bundel
    • ID Tim
    • Token
  3. Pilih Kotak pasir.

  4. Pilih Simpan.

Mengonfigurasi hub pemberitahuan Anda dengan informasi FCM

  1. Pilih Google (GCM/FCM) di bagian Pengaturan di menu sebelah kiri.
  2. Masukkan kunci server yang Anda catat dari Google Firebase Console.
  3. Pilih Simpan pada toolbar.

Membuat aplikasi backend ASP.NET Core Web API

Di bagian ini, Anda membuat backend ASP.NET Core Web API untuk menangani pendaftaran perangkat dan pengiriman pemberitahuan ke aplikasi seluler Xamarin.Forms.

Membuat proyek web

  1. Di Visual Studio, pilih File>Solusi Baru.

  2. Pilih .NET Core>App>ASP.NET Core>API>Berikutnya.

  3. Dalam dialog Konfigurasikan ASP.NET Core Web API baru Anda , pilih Kerangka Kerja Target.NET Core 3.1.

  4. Masukkan PushDemoApi untuk Nama Proyek lalu pilih Buat.

  5. Mulai penelusuran kesalahan (Command + Enter) untuk menguji aplikasi templat.

    Catatan

    Aplikasi templat dikonfigurasi untuk menggunakan WeatherForecastController sebagai launchUrl. Ini diatur dalam launchSettings.json Properti>.

    Jika Anda diminta dengan pesan sertifikat pengembangan yang ditemukan tidak valid :

    1. Klik Ya untuk menyetujui menjalankan alat 'dotnet dev-certs https' untuk memperbaikinya. Alat 'dotnet dev-certs https' kemudian meminta Anda untuk memasukkan kata sandi untuk sertifikat dan kata sandi untuk Rantai Kunci Anda.

    2. Klik Ya saat diminta untuk Menginstal dan mempercayai sertifikat baru, lalu masukkan kata sandi untuk Rantai Kunci Anda.

  6. Perluas folder Pengontrol , lalu hapus WeatherForecastController.cs.

  7. Hapus WeatherForecast.cs.

  8. Siapkan nilai konfigurasi lokal menggunakan alat Secret Manager. Memisahkan rahasia dari solusi memastikan bahwa rahasia tersebut tidak berakhir di kontrol sumber. Buka Terminal lalu buka direktori file proyek dan jalankan perintah berikut:

    dotnet user-secrets init
    dotnet user-secrets set "NotificationHub:Name" <value>
    dotnet user-secrets set "NotificationHub:ConnectionString" <value>
    

    Ganti nilai tempat penampung dengan nama hub pemberitahuan Anda sendiri dan nilai string koneksi. Anda mencatatnya di bagian buat hub pemberitahuan . Jika tidak, Anda dapat mencarinya di Azure.

    NotificationHub:Name:
    Lihat Nama di ringkasan Esensial di bagian atas Gambaran Umum.

    NotificationHub:ConnectionString:
    Lihat DefaultFullSharedAccessSignature dalam Kebijakan Akses

    Catatan

    Untuk skenario produksi, Anda dapat melihat opsi seperti Azure KeyVault untuk menyimpan string koneksi dengan aman. Untuk kesederhanaan, rahasia akan ditambahkan ke pengaturan aplikasi Azure App Service.

Mengautentikasi klien menggunakan Kunci API (Opsional)

Kunci API tidak seaman token, tetapi cukup untuk tujuan tutorial ini. Kunci API dapat dikonfigurasi dengan mudah melalui ASP.NET Middleware.

  1. Tambahkan kunci API ke nilai konfigurasi lokal.

    dotnet user-secrets set "Authentication:ApiKey" <value>
    

    Catatan

    Anda harus mengganti nilai tempat penampung dengan nilai Anda sendiri dan mencatatnya.

  2. Kontrol + Klik proyek PushDemoApi , pilih Folder Baru dari menu Tambahkan , lalu klik Tambahkan menggunakan Autentikasi sebagai Nama Folder.

  3. Kontrol + Klik folder Autentikasi , lalu pilih File Baru... dari menu Tambahkan .

  4. PilihKelas KosongUmum>, masukkan ApiKeyAuthOptions.cs untuk Nama, lalu klik Baru menambahkan implementasi berikut.

    using Microsoft.AspNetCore.Authentication;
    
    namespace PushDemoApi.Authentication
    {
        public class ApiKeyAuthOptions : AuthenticationSchemeOptions
        {
            public const string DefaultScheme = "ApiKey";
            public string Scheme => DefaultScheme;
            public string ApiKey { get; set; }
        }
    }
    
  5. Tambahkan Kelas Kosong lain ke folder Autentikasi yang disebut ApiKeyAuthHandler.cs, lalu tambahkan implementasi berikut.

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Security.Claims;
    using System.Text.Encodings.Web;
    using System.Threading.Tasks;
    using Microsoft.AspNetCore.Authentication;
    using Microsoft.Extensions.Logging;
    using Microsoft.Extensions.Options;
    
    namespace PushDemoApi.Authentication
    {
        public class ApiKeyAuthHandler : AuthenticationHandler<ApiKeyAuthOptions>
        {
            const string ApiKeyIdentifier = "apikey";
    
            public ApiKeyAuthHandler(
                IOptionsMonitor<ApiKeyAuthOptions> options,
                ILoggerFactory logger,
                UrlEncoder encoder,
                ISystemClock clock)
                : base(options, logger, encoder, clock) {}
    
            protected override Task<AuthenticateResult> HandleAuthenticateAsync()
            {
                string key = string.Empty;
    
                if (Request.Headers[ApiKeyIdentifier].Any())
                {
                    key = Request.Headers[ApiKeyIdentifier].FirstOrDefault();
                }
                else if (Request.Query.ContainsKey(ApiKeyIdentifier))
                {
                    if (Request.Query.TryGetValue(ApiKeyIdentifier, out var queryKey))
                        key = queryKey;
                }
    
                if (string.IsNullOrWhiteSpace(key))
                    return Task.FromResult(AuthenticateResult.Fail("No api key provided"));
    
                if (!string.Equals(key, Options.ApiKey, StringComparison.Ordinal))
                    return Task.FromResult(AuthenticateResult.Fail("Invalid api key."));
    
                var identities = new List<ClaimsIdentity> {
                    new ClaimsIdentity("ApiKeyIdentity")
                };
    
                var ticket = new AuthenticationTicket(
                    new ClaimsPrincipal(identities), Options.Scheme);
    
                return Task.FromResult(AuthenticateResult.Success(ticket));
            }
        }
    }
    

    Catatan

    Handler Autentikasi adalah jenis yang mengimplementasikan perilaku skema, dalam hal ini skema Kunci API kustom.

  6. Tambahkan Kelas Kosong lain ke folder Autentikasi yang disebut ApiKeyAuthenticationBuilderExtensions.cs, lalu tambahkan implementasi berikut.

    using System;
    using Microsoft.AspNetCore.Authentication;
    
    namespace PushDemoApi.Authentication
    {
        public static class AuthenticationBuilderExtensions
        {
            public static AuthenticationBuilder AddApiKeyAuth(
                this AuthenticationBuilder builder,
                Action<ApiKeyAuthOptions> configureOptions)
            {
                return builder
                    .AddScheme<ApiKeyAuthOptions, ApiKeyAuthHandler>(
                        ApiKeyAuthOptions.DefaultScheme,
                        configureOptions);
            }
        }
    }
    

    Catatan

    Metode ekstensi ini menyederhanakan kode konfigurasi middleware dalam Startup.cs membuatnya lebih mudah dibaca dan umumnya lebih mudah diikuti.

  7. Di Startup.cs, perbarui metode ConfigureServices untuk mengonfigurasi autentikasi Kunci API di bawah panggilan ke layanan. Metode AddControllers .

    using PushDemoApi.Authentication;
    using PushDemoApi.Models;
    using PushDemoApi.Services;
    
    public void ConfigureServices(IServiceCollection services)
    {
        services.AddControllers();
    
        services.AddAuthentication(options =>
        {
            options.DefaultAuthenticateScheme = ApiKeyAuthOptions.DefaultScheme;
            options.DefaultChallengeScheme = ApiKeyAuthOptions.DefaultScheme;
        }).AddApiKeyAuth(Configuration.GetSection("Authentication").Bind);
    }
    
  8. Masih dalam Startup.cs, perbarui metode Konfigurasi untuk memanggil metode ekstensi UseAuthentication dan UseAuthorization pada IApplicationBuilder aplikasi. Pastikan metode tersebut dipanggil setelah UseRouting dan sebelum aplikasi. Gunakan Titik Akhir.

    public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
    {
        if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
        }
    
        app.UseHttpsRedirection();
    
        app.UseRouting();
    
        app.UseAuthentication();
    
        app.UseAuthorization();
    
        app.UseEndpoints(endpoints =>
        {
            endpoints.MapControllers();
        });
    }
    

    Catatan

    Memanggil UseAuthentication mendaftarkan middleware yang menggunakan skema autentikasi yang terdaftar sebelumnya (dari ConfigureServices). Ini harus dipanggil sebelum middleware apa pun yang bergantung pada pengguna yang diautentikasi.

Menambahkan dependensi dan mengonfigurasi layanan

ASP.NET Core mendukung pola desain perangkat lunak injeksi dependensi (DI ), yang merupakan teknik untuk mencapai Inversion of Control (IoC) antara kelas dan dependensinya.

Penggunaan hub pemberitahuan dan Notification Hubs SDK untuk operasi backend dienkapsulasi dalam layanan. Layanan ini terdaftar dan tersedia melalui abstraksi yang sesuai.

  1. Kontrol + Klik folder Dependensi , lalu pilih Kelola Paket NuGet....

  2. Cari Microsoft.Azure.NotificationHubs dan pastikan diperiksa.

  3. Klik Tambahkan Paket, lalu klik Terima saat diminta untuk menerima persyaratan lisensi.

  4. Kontrol + Klik proyek PushDemoApi , pilih Folder Baru dari menu Tambahkan , lalu klik Tambahkan menggunakan Model sebagai Nama Folder.

  5. Kontrol + Klik folder Model , lalu pilih File Baru... dari menu Tambahkan .

  6. PilihKelas KosongUmum>, masukkan PushTemplates.cs untuk Nama, lalu klik Baru menambahkan implementasi berikut.

    namespace PushDemoApi.Models
    {
        public class PushTemplates
        {
            public class Generic
            {
                public const string Android = "{ \"notification\": { \"title\" : \"PushDemo\", \"body\" : \"$(alertMessage)\"}, \"data\" : { \"action\" : \"$(alertAction)\" } }";
                public const string iOS = "{ \"aps\" : {\"alert\" : \"$(alertMessage)\"}, \"action\" : \"$(alertAction)\" }";
            }
    
            public class Silent
            {
                public const string Android = "{ \"data\" : {\"message\" : \"$(alertMessage)\", \"action\" : \"$(alertAction)\"} }";
                public const string iOS = "{ \"aps\" : {\"content-available\" : 1, \"apns-priority\": 5, \"sound\" : \"\", \"badge\" : 0}, \"message\" : \"$(alertMessage)\", \"action\" : \"$(alertAction)\" }";
            }
        }
    }
    

    Catatan

    Kelas ini berisi payload pemberitahuan yang ditokenisasi untuk pemberitahuan generik dan senyap yang diperlukan oleh skenario ini. Payload didefinisikan di luar Penginstalan untuk memungkinkan eksperimen tanpa harus memperbarui penginstalan yang ada melalui layanan. Menangani perubahan pada penginstalan dengan cara ini di luar cakupan untuk tutorial ini. Untuk produksi, pertimbangkan templat kustom.

  7. Tambahkan Kelas Kosong lain ke folder Model yang disebut DeviceInstallation.cs, lalu tambahkan implementasi berikut.

    using System.Collections.Generic;
    using System.ComponentModel.DataAnnotations;
    
    namespace PushDemoApi.Models
    {
        public class DeviceInstallation
        {
            [Required]
            public string InstallationId { get; set; }
    
            [Required]
            public string Platform { get; set; }
    
            [Required]
            public string PushChannel { get; set; }
    
            public IList<string> Tags { get; set; } = Array.Empty<string>();
        }
    }
    
  8. Tambahkan Kelas Kosong lain ke folder Model yang disebut NotificationRequest.cs, lalu tambahkan implementasi berikut.

    using System;
    
    namespace PushDemoApi.Models
    {
        public class NotificationRequest
        {
            public string Text { get; set; }
            public string Action { get; set; }
            public string[] Tags { get; set; } = Array.Empty<string>();
            public bool Silent { get; set; }
        }
    }
    
  9. Tambahkan Kelas Kosong lain ke folder Model yang disebut NotificationHubOptions.cs, lalu tambahkan implementasi berikut.

    using System.ComponentModel.DataAnnotations;
    
    namespace PushDemoApi.Models
    {
        public class NotificationHubOptions
        {
            [Required]
            public string Name { get; set; }
    
            [Required]
            public string ConnectionString { get; set; }
        }
    }
    
  10. Tambahkan folder baru ke proyek PushDemoApi yang disebut Layanan.

  11. Tambahkan Antarmuka Kosong ke folder Layanan yang disebut INotificationService.cs, lalu tambahkan implementasi berikut.

    using System.Threading;
    using System.Threading.Tasks;
    using PushDemoApi.Models;
    
    namespace PushDemoApi.Services
    {
        public interface INotificationService
        {
            Task<bool> CreateOrUpdateInstallationAsync(DeviceInstallation deviceInstallation, CancellationToken token);
            Task<bool> DeleteInstallationByIdAsync(string installationId, CancellationToken token);
            Task<bool> RequestNotificationAsync(NotificationRequest notificationRequest, CancellationToken token);
        }
    }
    
  12. Tambahkan Kelas Kosong ke folder Layanan yang disebut NotificationHubsService.cs, lalu tambahkan kode berikut untuk mengimplementasikan antarmuka INotificationService :

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Threading;
    using System.Threading.Tasks;
    using Microsoft.Azure.NotificationHubs;
    using Microsoft.Extensions.Logging;
    using Microsoft.Extensions.Options;
    using PushDemoApi.Models;
    
    namespace PushDemoApi.Services
    {
        public class NotificationHubService : INotificationService
        {
            readonly NotificationHubClient _hub;
            readonly Dictionary<string, NotificationPlatform> _installationPlatform;
            readonly ILogger<NotificationHubService> _logger;
    
            public NotificationHubService(IOptions<NotificationHubOptions> options, ILogger<NotificationHubService> logger)
            {
                _logger = logger;
                _hub = NotificationHubClient.CreateClientFromConnectionString(
                    options.Value.ConnectionString,
                    options.Value.Name);
    
                _installationPlatform = new Dictionary<string, NotificationPlatform>
                {
                    { nameof(NotificationPlatform.Apns).ToLower(), NotificationPlatform.Apns },
                    { nameof(NotificationPlatform.Fcm).ToLower(), NotificationPlatform.Fcm }
                };
            }
    
            public async Task<bool> CreateOrUpdateInstallationAsync(DeviceInstallation deviceInstallation, CancellationToken token)
            {
                if (string.IsNullOrWhiteSpace(deviceInstallation?.InstallationId) ||
                    string.IsNullOrWhiteSpace(deviceInstallation?.Platform) ||
                    string.IsNullOrWhiteSpace(deviceInstallation?.PushChannel))
                    return false;
    
                var installation = new Installation()
                {
                    InstallationId = deviceInstallation.InstallationId,
                    PushChannel = deviceInstallation.PushChannel,
                    Tags = deviceInstallation.Tags
                };
    
                if (_installationPlatform.TryGetValue(deviceInstallation.Platform, out var platform))
                    installation.Platform = platform;
                else
                    return false;
    
                try
                {
                    await _hub.CreateOrUpdateInstallationAsync(installation, token);
                }
                catch
                {
                    return false;
                }
    
                return true;
            }
    
            public async Task<bool> DeleteInstallationByIdAsync(string installationId, CancellationToken token)
            {
                if (string.IsNullOrWhiteSpace(installationId))
                    return false;
    
                try
                {
                    await _hub.DeleteInstallationAsync(installationId, token);
                }
                catch
                {
                    return false;
                }
    
                return true;
            }
    
            public async Task<bool> RequestNotificationAsync(NotificationRequest notificationRequest, CancellationToken token)
            {
                if ((notificationRequest.Silent &&
                    string.IsNullOrWhiteSpace(notificationRequest?.Action)) ||
                    (!notificationRequest.Silent &&
                    (string.IsNullOrWhiteSpace(notificationRequest?.Text)) ||
                    string.IsNullOrWhiteSpace(notificationRequest?.Action)))
                    return false;
    
                var androidPushTemplate = notificationRequest.Silent ?
                    PushTemplates.Silent.Android :
                    PushTemplates.Generic.Android;
    
                var iOSPushTemplate = notificationRequest.Silent ?
                    PushTemplates.Silent.iOS :
                    PushTemplates.Generic.iOS;
    
                var androidPayload = PrepareNotificationPayload(
                    androidPushTemplate,
                    notificationRequest.Text,
                    notificationRequest.Action);
    
                var iOSPayload = PrepareNotificationPayload(
                    iOSPushTemplate,
                    notificationRequest.Text,
                    notificationRequest.Action);
    
                try
                {
                    if (notificationRequest.Tags.Length == 0)
                    {
                        // This will broadcast to all users registered in the notification hub
                        await SendPlatformNotificationsAsync(androidPayload, iOSPayload, token);
                    }
                    else if (notificationRequest.Tags.Length <= 20)
                    {
                        await SendPlatformNotificationsAsync(androidPayload, iOSPayload, notificationRequest.Tags, token);
                    }
                    else
                    {
                        var notificationTasks = notificationRequest.Tags
                            .Select((value, index) => (value, index))
                            .GroupBy(g => g.index / 20, i => i.value)
                            .Select(tags => SendPlatformNotificationsAsync(androidPayload, iOSPayload, tags, token));
    
                        await Task.WhenAll(notificationTasks);
                    }
    
                    return true;
                }
                catch (Exception e)
                {
                    _logger.LogError(e, "Unexpected error sending notification");
                    return false;
                }
            }
    
            string PrepareNotificationPayload(string template, string text, string action) => template
                .Replace("$(alertMessage)", text, StringComparison.InvariantCulture)
                .Replace("$(alertAction)", action, StringComparison.InvariantCulture);
    
            Task SendPlatformNotificationsAsync(string androidPayload, string iOSPayload, CancellationToken token)
            {
                var sendTasks = new Task[]
                {
                    _hub.SendFcmNativeNotificationAsync(androidPayload, token),
                    _hub.SendAppleNativeNotificationAsync(iOSPayload, token)
                };
    
                return Task.WhenAll(sendTasks);
            }
    
            Task SendPlatformNotificationsAsync(string androidPayload, string iOSPayload, IEnumerable<string> tags, CancellationToken token)
            {
                var sendTasks = new Task[]
                {
                    _hub.SendFcmNativeNotificationAsync(androidPayload, tags, token),
                    _hub.SendAppleNativeNotificationAsync(iOSPayload, tags, token)
                };
    
                return Task.WhenAll(sendTasks);
            }
        }
    }
    

    Catatan

    Ekspresi tag yang disediakan untuk SendTemplateNotificationAsync dibatasi hingga 20 tag. Ini dibatasi hingga 6 untuk sebagian besar operator tetapi ekspresi hanya berisi OU (||) dalam hal ini. Jika ada lebih dari 20 tag dalam permintaan, tag tersebut harus dibagi menjadi beberapa permintaan. Lihat dokumentasi Perutean dan Ekspresi Tag untuk detail selengkapnya.

  13. Di Startup.cs, perbarui metode ConfigureServices untuk menambahkan NotificationHubsService sebagai implementasi database tunggal INotificationService.

    
    using PushDemoApi.Models;
    using PushDemoApi.Services;
    
    public void ConfigureServices(IServiceCollection services)
    {
        ...
    
        services.AddSingleton<INotificationService, NotificationHubService>();
    
        services.AddOptions<NotificationHubOptions>()
            .Configure(Configuration.GetSection("NotificationHub").Bind)
            .ValidateDataAnnotations();
    }
    

Membuat API pemberitahuan

  1. Kontrol + Klik folder Pengontrol , lalu pilih File Baru... dari menu Tambahkan .

  2. Pilih ASP.NET>Core Web API Controller Class, masukkan NotificationsController untuk Nama, lalu klik Baru.

    Catatan

    Jika Anda mengikuti Visual Studio 2019, pilih Pengontrol API dengan templat tindakan baca/tulis .

  3. Tambahkan namespace berikut ke bagian atas file.

    using System.ComponentModel.DataAnnotations;
    using System.Net;
    using System.Threading;
    using System.Threading.Tasks;
    using Microsoft.AspNetCore.Authorization;
    using Microsoft.AspNetCore.Mvc;
    using PushDemoApi.Models;
    using PushDemoApi.Services;
    
  4. Perbarui pengontrol templat sehingga berasal dari ControllerBase dan didekorasi dengan atribut ApiController .

    [ApiController]
    [Route("api/[controller]")]
    public class NotificationsController : ControllerBase
    {
        // Templated methods here
    }
    

    Catatan

    Kelas dasar Pengontrol menyediakan dukungan untuk tampilan tetapi ini tidak diperlukan dalam hal ini sehingga ControllerBase dapat digunakan sebagai gantinya. Jika Mengikuti Visual Studio 2019, Anda dapat melewati langkah ini.

  5. Jika Anda memilih untuk menyelesaikan klien Autentikasi menggunakan bagian Kunci API , Anda juga harus menghias NotificationsController dengan atribut Otorisasi .

    [Authorize]
    
  6. Perbarui konstruktor untuk menerima instans terdaftar INotificationService sebagai argumen dan tetapkan ke anggota readonly.

    readonly INotificationService _notificationService;
    
    public NotificationsController(INotificationService notificationService)
    {
        _notificationService = notificationService;
    }
    
  7. Di launchSettings.json (dalam folder Properti ), ubah launchUrl dari weatherforecast ke api/pemberitahuan agar sesuai dengan URL yang ditentukan dalam atribut RegistrationsControllerRoute .

  8. Mulai penelusuran kesalahan (Command + Enter) untuk memvalidasi aplikasi bekerja dengan NotificationsController baru dan mengembalikan status Tidak Sah 401 .

    Catatan

    Visual Studio mungkin tidak secara otomatis meluncurkan aplikasi di browser. Anda akan menggunakan Postman untuk menguji API mulai saat ini.

  9. Pada tab Postman baru, atur permintaan ke GET. Masukkan alamat di bawah ini mengganti applicationUrl> tempat penampung< dengan applicationUrl https yang ditemukan di Properti>launchSettings.json.

    <applicationUrl>/api/notifications
    

    Catatan

    applicationUrl harus 'https://localhost:5001' untuk profil default. Jika Anda menggunakan IIS (default di Visual Studio 2019 di Windows), Anda harus menggunakan applicationUrl yang ditentukan dalam item iisSettings sebagai gantinya. Anda akan menerima respons 404 jika alamat salah.

  10. Jika Anda memilih untuk menyelesaikan klien Autentikasi menggunakan bagian Kunci API , pastikan untuk mengonfigurasi header permintaan untuk menyertakan nilai apikey Anda.

    Kunci Nilai
    apikey <your_api_key>
  11. Klik tombol Kirim .

    Catatan

    Anda akan menerima status 200 OK dengan beberapa konten JSON .

    Jika Anda menerima peringatan verifikasi sertifikat SSL , Anda dapat mengalihkan pengaturan postman verifikasi sertifikat SSL permintaan di Pengaturan.

  12. Ganti metode kelas templat di NotificationsController.cs dengan kode berikut.

    [HttpPut]
    [Route("installations")]
    [ProducesResponseType((int)HttpStatusCode.OK)]
    [ProducesResponseType((int)HttpStatusCode.BadRequest)]
    [ProducesResponseType((int)HttpStatusCode.UnprocessableEntity)]
    public async Task<IActionResult> UpdateInstallation(
        [Required]DeviceInstallation deviceInstallation)
    {
        var success = await _notificationService
            .CreateOrUpdateInstallationAsync(deviceInstallation, HttpContext.RequestAborted);
    
        if (!success)
            return new UnprocessableEntityResult();
    
        return new OkResult();
    }
    
    [HttpDelete()]
    [Route("installations/{installationId}")]
    [ProducesResponseType((int)HttpStatusCode.OK)]
    [ProducesResponseType((int)HttpStatusCode.BadRequest)]
    [ProducesResponseType((int)HttpStatusCode.UnprocessableEntity)]
    public async Task<ActionResult> DeleteInstallation(
        [Required][FromRoute]string installationId)
    {
        var success = await _notificationService
            .DeleteInstallationByIdAsync(installationId, CancellationToken.None);
    
        if (!success)
            return new UnprocessableEntityResult();
    
        return new OkResult();
    }
    
    [HttpPost]
    [Route("requests")]
    [ProducesResponseType((int)HttpStatusCode.OK)]
    [ProducesResponseType((int)HttpStatusCode.BadRequest)]
    [ProducesResponseType((int)HttpStatusCode.UnprocessableEntity)]
    public async Task<IActionResult> RequestPush(
        [Required]NotificationRequest notificationRequest)
    {
        if ((notificationRequest.Silent &&
            string.IsNullOrWhiteSpace(notificationRequest?.Action)) ||
            (!notificationRequest.Silent &&
            string.IsNullOrWhiteSpace(notificationRequest?.Text)))
            return new BadRequestResult();
    
        var success = await _notificationService
            .RequestNotificationAsync(notificationRequest, HttpContext.RequestAborted);
    
        if (!success)
            return new UnprocessableEntityResult();
    
        return new OkResult();
    }
    

Membuat aplikasi API

Anda sekarang membuat Aplikasi API di Azure App Service untuk menghosting layanan backend.

  1. Masuk ke portal Azure.

  2. Klik Buat sumber daya, lalu cari dan pilih Aplikasi API, lalu klik Buat.

  3. Perbarui bidang berikut, lalu klik Buat.

    Nama aplikasi:
    Masukkan nama unik global untuk Aplikasi API

    Berlangganan:
    Pilih Langganan target yang sama dengan tempat Anda membuat hub pemberitahuan.

    Grup Sumber Daya:
    Pilih Grup Sumber Daya yang sama dengan tempat Anda membuat hub pemberitahuan.

    Rencana/Lokasi App Service:
    Membuat Paket App Service baru

    Catatan

    Ubah dari opsi default menjadi paket yang menyertakan dukungan SSL . Jika tidak, Anda harus mengambil langkah-langkah yang sesuai saat bekerja dengan aplikasi seluler untuk mencegah permintaan http diblokir.

    Application Insights:
    Pertahankan opsi yang disarankan (sumber daya baru akan dibuat menggunakan nama tersebut) atau pilih sumber daya yang ada.

  4. Setelah Aplikasi API disediakan, navigasikan ke sumber daya tersebut.

  5. Catat properti URL di ringkasan Esensial di bagian atas Gambaran Umum. URL ini adalah titik akhir backend Anda yang akan digunakan nanti dalam tutorial ini.

    Catatan

    URL menggunakan nama aplikasi API yang Anda tentukan sebelumnya, dengan format https://<app_name>.azurewebsites.net.

  6. Pilih Konfigurasi dari daftar (di bawah Pengaturan).

  7. Untuk setiap pengaturan di bawah ini, klik Pengaturan aplikasi baru untuk memasukkan Nama dan Nilai, lalu klik OK.

    Nama Nilai
    Authentication:ApiKey <api_key_value>
    NotificationHub:Name <hub_name_value>
    NotificationHub:ConnectionString <hub_connection_string_value>

    Catatan

    Ini adalah pengaturan yang sama dengan yang Anda tentukan sebelumnya di pengaturan pengguna. Anda harus dapat menyalin ini. Pengaturan Authentication:ApiKey diperlukan hanya jika Anda memilih untuk menyelesaikan bagian Autentikasi klien menggunakan Kunci API . Untuk skenario produksi, Anda dapat melihat opsi seperti Azure KeyVault. Ini telah ditambahkan sebagai pengaturan aplikasi untuk kesederhanaan dalam kasus ini.

  8. Setelah semua pengaturan aplikasi ditambahkan, klik Simpan, lalu Lanjutkan.

Menerbitkan layanan backend

Selanjutnya, Anda menyebarkan aplikasi ke Aplikasi API untuk membuatnya dapat diakses dari semua perangkat.

Catatan

Langkah-langkah berikut khusus untuk Visual Studio untuk Mac. Jika Anda mengikuti Visual Studio 2019 di Windows, alur penerbitan akan berbeda. Lihat Menerbitkan ke Azure App Service di Windows.

  1. Ubah konfigurasi Anda dari Debug ke Rilis jika Anda belum melakukannya.

  2. Kontrol + Klik proyek PushDemoApi , lalu pilih Terbitkan ke Azure... dari menu Terbitkan .

  3. Ikuti alur autentikasi jika diminta untuk melakukannya. Gunakan akun yang Anda gunakan di bagian buat Aplikasi API sebelumnya.

  4. Pilih aplikasi Azure App Service API yang Anda buat sebelumnya dari daftar sebagai target publikasi Anda, lalu klik Terbitkan.

Setelah Anda menyelesaikan wizard, wizard akan menerbitkan aplikasi ke Azure lalu membuka aplikasi. Catat URL jika Anda belum melakukannya. URL ini adalah titik akhir backend Anda yang digunakan nanti dalam tutorial ini.

Memvalidasi API yang diterbitkan

  1. Di Postman buka tab baru, atur permintaan ke PUT dan masukkan alamat di bawah ini. Ganti tempat penampung dengan alamat dasar yang Anda catat di bagian terbitkan layanan backend sebelumnya.

    https://<app_name>.azurewebsites.net/api/notifications/installations
    

    Catatan

    Alamat dasar harus dalam format https://<app_name>.azurewebsites.net/

  2. Jika Anda memilih untuk menyelesaikan klien Autentikasi menggunakan bagian Kunci API , pastikan untuk mengonfigurasi header permintaan untuk menyertakan nilai apikey Anda.

    Kunci Nilai
    apikey <your_api_key>
  3. Pilih opsi mentah untuk Isi, lalu pilih JSON dari daftar opsi format, lalu sertakan beberapa konten JSON tempat penampung:

    {}
    
  4. Klik Kirim.

    Catatan

    Anda harus menerima status UnprocessableEntity 422 dari layanan.

  5. Lakukan langkah 1-4 lagi tetapi kali ini menentukan titik akhir permintaan untuk memvalidasi Anda menerima respons 400 Permintaan Buruk .

    https://<app_name>.azurewebsites.net/api/notifications/requests
    

Catatan

Belum dimungkinkan untuk menguji API menggunakan data permintaan yang valid karena ini akan memerlukan informasi khusus platform dari aplikasi seluler klien.

Membuat aplikasi Xamarin.Forms lintas platform

Di bagian ini, Anda membangun aplikasi seluler Xamarin.Forms yang menerapkan pemberitahuan push secara lintas platform.

Ini memungkinkan Anda untuk mendaftar dan membatalkan pendaftaran dari hub pemberitahuan melalui layanan backend yang Anda buat.

Pemberitahuan ditampilkan saat tindakan ditentukan dan aplikasi berada di latar depan. Jika tidak, pemberitahuan muncul di pusat pemberitahuan.

Catatan

Anda biasanya akan melakukan tindakan pendaftaran (dan deregistrasi) selama titik yang sesuai dalam siklus hidup aplikasi (atau sebagai bagian dari pengalaman pertama Anda mungkin) tanpa input pendaftaran/deregister pengguna eksplisit. Namun, contoh ini akan memerlukan input pengguna eksplisit untuk memungkinkan fungsionalitas ini dieksplorasi dan diuji dengan lebih mudah.

Membuat solusi Xamarin.Forms

  1. Di Visual Studio, buat solusi Xamarin.Forms baru menggunakan Aplikasi Formulir Kosong sebagai templat dan masukkan PushDemo untuk Nama Proyek.

    Catatan

    Dalam dialog Konfigurasikan Aplikasi Formulir Kosong Anda , pastikan Pengidentifikasi Organisasi cocok dengan nilai yang Anda gunakan sebelumnya dan target Android dan iOS dicentang.

  2. Kontrol + Klik pada solusi PushDemo , lalu pilih Perbarui Paket NuGet.

  3. Kontrol + Klik pada solusi PushDemo , lalu pilih Kelola Paket NuGet...

  4. Cari Newtonsoft.Json dan pastikan diperiksa.

  5. Klik Tambahkan Paket, lalu klik Terima saat diminta untuk menerima persyaratan lisensi.

  6. Buat dan jalankan aplikasi di setiap platform target (Command + Enter) untuk menguji aplikasi templat yang berjalan di perangkat Anda.

Menerapkan komponen lintas platform

  1. Kontrol + Klik proyek PushDemo , pilih Folder Baru dari menu Tambahkan , lalu klik Tambahkan menggunakan Model sebagai Nama Folder.

  2. Kontrol + Klik folder Model , lalu pilih File Baru... dari menu Tambahkan .

  3. PilihKelas KosongUmum>, masukkan DeviceInstallation.cs, lalu tambahkan implementasi berikut.

    using System.Collections.Generic;
    using Newtonsoft.Json;
    
    namespace PushDemo.Models
    {
        public class DeviceInstallation
        {
            [JsonProperty("installationId")]
            public string InstallationId { get; set; }
    
            [JsonProperty("platform")]
            public string Platform { get; set; }
    
            [JsonProperty("pushChannel")]
            public string PushChannel { get; set; }
    
            [JsonProperty("tags")]
            public List<string> Tags { get; set; } = new List<string>();
        }
    }
    
  4. Tambahkan Enumerasi Kosong ke folder Model yang disebut PushDemoAction.cs dengan implementasi berikut.

    namespace PushDemo.Models
    {
        public enum PushDemoAction
        {
            ActionA,
            ActionB
        }
    }
    
  5. Tambahkan folder baru ke proyek PushDemo yang disebut Layanan lalu tambahkan Kelas Kosong ke folder yang disebut ServiceContainer.cs dengan implementasi berikut.

    using System;
    using System.Collections.Generic;
    
    namespace PushDemo.Services
    {
       public static class ServiceContainer
       {
           static readonly Dictionary<Type, Lazy<object>> services
               = new Dictionary<Type, Lazy<object>>();
    
           public static void Register<T>(Func<T> function)
               => services[typeof(T)] = new Lazy<object>(() => function());
    
           public static T Resolve<T>()
               => (T)Resolve(typeof(T));
    
           public static object Resolve(Type type)
           {
               {
                   if (services.TryGetValue(type, out var service))
                       return service.Value;
    
                   throw new KeyNotFoundException($"Service not found for type '{type}'");
               }
           }
       }
    }
    

    Catatan

    Ini adalah versi kelas ServiceContainer yang dipangkas dari repositori XamCAT . Ini akan digunakan sebagai kontainer IoC (Inversion of Control) ringan.

  6. Tambahkan Antarmuka Kosong ke folder Layanan yang disebut IDeviceInstallationService.cs, lalu tambahkan kode berikut.

    using PushDemo.Models;
    
    namespace PushDemo.Services
    {
        public interface IDeviceInstallationService
        {
            string Token { get; set; }
            bool NotificationsSupported { get; }
            string GetDeviceId();
            DeviceInstallation GetDeviceInstallation(params string[] tags);
        }
    }
    

    Catatan

    Antarmuka ini akan diimplementasikan dan di-bootstrap oleh setiap target nanti untuk menyediakan fungsionalitas khusus platform dan informasi DeviceInstallation yang diperlukan oleh layanan backend.

  7. Tambahkan Antarmuka Kosong lain ke folder Layanan yang disebut INotificationRegistrationService.cs, lalu tambahkan kode berikut.

    using System.Threading.Tasks;
    
    namespace PushDemo.Services
    {
        public interface INotificationRegistrationService
        {
            Task DeregisterDeviceAsync();
            Task RegisterDeviceAsync(params string[] tags);
            Task RefreshRegistrationAsync();
        }
    }
    

    Catatan

    Ini akan menangani interaksi antara klien dan layanan backend.

  8. Tambahkan Antarmuka Kosong lain ke folder Layanan yang disebut INotificationActionService.cs, lalu tambahkan kode berikut.

    namespace PushDemo.Services
    {
        public interface INotificationActionService
        {
            void TriggerAction(string action);
        }
    }
    

    Catatan

    Ini digunakan sebagai mekanisme sederhana untuk mempusatkan penanganan tindakan pemberitahuan.

  9. Tambahkan Antarmuka Kosong ke folder Layanan yang disebut IPushDemoNotificationActionService.cs yang berasal dari INotificationActionService, dengan implementasi berikut.

    using System;
    using PushDemo.Models;
    
    namespace PushDemo.Services
    {
        public interface IPushDemoNotificationActionService : INotificationActionService
        {
            event EventHandler<PushDemoAction> ActionTriggered;
        }
    }
    

    Catatan

    Jenis ini khusus untuk aplikasi PushDemo dan menggunakan enumerasi PushDemoAction untuk mengidentifikasi tindakan yang dipicu dengan cara yang sangat ditik.

  10. Tambahkan Kelas Kosong ke folder Layanan yang disebut NotificationRegistrationService.cs menerapkan INotificationRegistrationService dengan kode berikut.

    using System;
    using System.Net.Http;
    using System.Text;
    using System.Threading.Tasks;
    using Newtonsoft.Json;
    using PushDemo.Models;
    using Xamarin.Essentials;
    
    namespace PushDemo.Services
    {
        public class NotificationRegistrationService : INotificationRegistrationService
        {
            const string RequestUrl = "api/notifications/installations";
            const string CachedDeviceTokenKey = "cached_device_token";
            const string CachedTagsKey = "cached_tags";
    
            string _baseApiUrl;
            HttpClient _client;
            IDeviceInstallationService _deviceInstallationService;
    
            public NotificationRegistrationService(string baseApiUri, string apiKey)
            {
                _client = new HttpClient();
                _client.DefaultRequestHeaders.Add("Accept", "application/json");
                _client.DefaultRequestHeaders.Add("apikey", apiKey);
    
                _baseApiUrl = baseApiUri;
            }
    
            IDeviceInstallationService DeviceInstallationService
                => _deviceInstallationService ??
                    (_deviceInstallationService = ServiceContainer.Resolve<IDeviceInstallationService>());
    
            public async Task DeregisterDeviceAsync()
            {
                var cachedToken = await SecureStorage.GetAsync(CachedDeviceTokenKey)
                    .ConfigureAwait(false);
    
                if (cachedToken == null)
                    return;
    
                var deviceId = DeviceInstallationService?.GetDeviceId();
    
                if (string.IsNullOrWhiteSpace(deviceId))
                    throw new Exception("Unable to resolve an ID for the device.");
    
                await SendAsync(HttpMethod.Delete, $"{RequestUrl}/{deviceId}")
                    .ConfigureAwait(false);
    
                SecureStorage.Remove(CachedDeviceTokenKey);
                SecureStorage.Remove(CachedTagsKey);
            }
    
            public async Task RegisterDeviceAsync(params string[] tags)
            {
                var deviceInstallation = DeviceInstallationService?.GetDeviceInstallation(tags);
    
                await SendAsync<DeviceInstallation>(HttpMethod.Put, RequestUrl, deviceInstallation)
                    .ConfigureAwait(false);
    
                await SecureStorage.SetAsync(CachedDeviceTokenKey, deviceInstallation.PushChannel)
                    .ConfigureAwait(false);
    
                await SecureStorage.SetAsync(CachedTagsKey, JsonConvert.SerializeObject(tags));
            }
    
            public async Task RefreshRegistrationAsync()
            {
                var cachedToken = await SecureStorage.GetAsync(CachedDeviceTokenKey)
                    .ConfigureAwait(false);
    
                var serializedTags = await SecureStorage.GetAsync(CachedTagsKey)
                    .ConfigureAwait(false);
    
                if (string.IsNullOrWhiteSpace(cachedToken) ||
                    string.IsNullOrWhiteSpace(serializedTags) ||
                    string.IsNullOrWhiteSpace(DeviceInstallationService.Token) ||
                    cachedToken == DeviceInstallationService.Token)
                    return;
    
                var tags = JsonConvert.DeserializeObject<string[]>(serializedTags);
    
                await RegisterDeviceAsync(tags);
            }
    
            async Task SendAsync<T>(HttpMethod requestType, string requestUri, T obj)
            {
                string serializedContent = null;
    
                await Task.Run(() => serializedContent = JsonConvert.SerializeObject(obj))
                    .ConfigureAwait(false);
    
                await SendAsync(requestType, requestUri, serializedContent);
            }
    
            async Task SendAsync(
                HttpMethod requestType,
                string requestUri,
                string jsonRequest = null)
            {
                var request = new HttpRequestMessage(requestType, new Uri($"{_baseApiUrl}{requestUri}"));
    
                if (jsonRequest != null)
                    request.Content = new StringContent(jsonRequest, Encoding.UTF8, "application/json");
    
                var response = await _client.SendAsync(request).ConfigureAwait(false);
    
                response.EnsureSuccessStatusCode();
            }
        }
    }
    

    Catatan

    Argumen apiKey hanya diperlukan jika Anda memilih untuk menyelesaikan klien Autentikasi menggunakan bagian Kunci API .

  11. Tambahkan Kelas Kosong ke folder Layanan yang disebut PushDemoNotificationActionService.cs menerapkan IPushDemoNotificationActionService dengan kode berikut.

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using PushDemo.Models;
    
    namespace PushDemo.Services
    {
        public class PushDemoNotificationActionService : IPushDemoNotificationActionService
        {
            readonly Dictionary<string, PushDemoAction> _actionMappings = new Dictionary<string, PushDemoAction>
            {
                { "action_a", PushDemoAction.ActionA },
                { "action_b", PushDemoAction.ActionB }
            };
    
            public event EventHandler<PushDemoAction> ActionTriggered = delegate { };
    
            public void TriggerAction(string action)
            {
                if (!_actionMappings.TryGetValue(action, out var pushDemoAction))
                    return;
    
                List<Exception> exceptions = new List<Exception>();
    
                foreach (var handler in ActionTriggered?.GetInvocationList())
                {
                    try
                    {
                        handler.DynamicInvoke(this, pushDemoAction);
                    }
                    catch (Exception ex)
                    {
                        exceptions.Add(ex);
                    }
                }
    
                if (exceptions.Any())
                    throw new AggregateException(exceptions);
            }
        }
    }
    
  12. Tambahkan Kelas Kosong ke proyek PushDemo yang disebut Config.cs dengan implementasi berikut.

    namespace PushDemo
    {
        public static partial class Config
        {
            public static string ApiKey = "API_KEY";
            public static string BackendServiceEndpoint = "BACKEND_SERVICE_ENDPOINT";
        }
    }
    

    Catatan

    Ini digunakan sebagai cara sederhana untuk menjaga rahasia di luar kontrol sumber. Anda dapat mengganti nilai-nilai ini sebagai bagian dari build otomatis atau mengambil alihnya menggunakan kelas parsial lokal. Anda akan melakukan ini di langkah berikutnya.

    Bidang ApiKey hanya diperlukan jika Anda memilih untuk menyelesaikan klien Autentikasi menggunakan bagian Kunci API .

  13. Tambahkan Kelas Kosong lain ke proyek PushDemo kali ini yang disebut Config.local_secrets.cs dengan implementasi berikut.

    namespace PushDemo
    {
        public static partial class Config
        {
            static Config()
            {
                ApiKey = "<your_api_key>";
                BackendServiceEndpoint = "<your_api_app_url>";
            }
        }
    }
    

    Catatan

    Ganti nilai tempat penampung dengan nilai Anda sendiri. Anda seharusnya mencatat ini ketika Anda membangun layanan backend. URL Aplikasi API harus https://<api_app_name>.azurewebsites.net/. Ingatlah untuk menambahkan *.local_secrets.* ke file gitignore Anda untuk menghindari penerapan file ini.

    Bidang ApiKey hanya diperlukan jika Anda memilih untuk menyelesaikan klien Autentikasi menggunakan bagian Kunci API .

  14. Tambahkan Kelas Kosong ke proyek PushDemo yang disebut Bootstrap.cs dengan implementasi berikut.

    using System;
    using PushDemo.Services;
    
    namespace PushDemo
    {
        public static class Bootstrap
        {
            public static void Begin(Func<IDeviceInstallationService> deviceInstallationService)
            {
                ServiceContainer.Register(deviceInstallationService);
    
                ServiceContainer.Register<IPushDemoNotificationActionService>(()
                    => new PushDemoNotificationActionService());
    
                ServiceContainer.Register<INotificationRegistrationService>(()
                    => new NotificationRegistrationService(
                        Config.BackendServiceEndpoint,
                        Config.ApiKey));
            }
        }
    }
    

    Catatan

    Metode Begin akan dipanggil oleh setiap platform ketika aplikasi diluncurkan melewati implementasi khusus platform IDeviceInstallationService.

    Argumen konstruktor NotificationRegistrationServiceapiKey hanya diperlukan jika Anda memilih untuk menyelesaikan klien Autentikasi menggunakan bagian Kunci API .

Menerapkan UI lintas platform

  1. Dalam proyek PushDemo , buka MainPage.xaml dan ganti kontrol StackLayout dengan yang berikut ini.

    <StackLayout VerticalOptions="EndAndExpand"  
                 HorizontalOptions="FillAndExpand"
                 Padding="20,40">
        <Button x:Name="RegisterButton"
                Text="Register"
                Clicked="RegisterButtonClicked" />
        <Button x:Name="DeregisterButton"
                Text="Deregister"
                Clicked="DeregisterButtonClicked" />
    </StackLayout>
    
  2. Sekarang di MainPage.xaml.cs, tambahkan bidang backing readonly untuk menyimpan referensi ke implementasi INotificationRegistrationService .

    readonly INotificationRegistrationService _notificationRegistrationService;
    
  3. Di konstruktor MainPage , selesaikan implementasi INotificationRegistrationService menggunakan ServiceContainer dan tetapkan ke bidang backing notificationRegistrationService .

    public MainPage()
    {
        InitializeComponent();
    
        _notificationRegistrationService =
            ServiceContainer.Resolve<INotificationRegistrationService>();
    }
    
  4. Terapkan penanganan aktivitas untuk tombol RegisterButton dan DeregisterButton Peristiwa yang diklik yang memanggil metode Register/Deregister yang sesuai.

    void RegisterButtonClicked(object sender, EventArgs e)
        => _notificationRegistrationService.RegisterDeviceAsync().ContinueWith((task)
            => { ShowAlert(task.IsFaulted ?
                    task.Exception.Message :
                    $"Device registered"); });
    
    void DeregisterButtonClicked(object sender, EventArgs e)
        => _notificationRegistrationService.DeregisterDeviceAsync().ContinueWith((task)
            => { ShowAlert(task.IsFaulted ?
                    task.Exception.Message :
                    $"Device deregistered"); });
    
    void ShowAlert(string message)
        => MainThread.BeginInvokeOnMainThread(()
            => DisplayAlert("PushDemo", message, "OK").ContinueWith((task)
                => { if (task.IsFaulted) throw task.Exception; }));
    
  5. Sekarang di App.xaml.cs, pastikan namespace berikut dirujuk.

    using PushDemo.Models;
    using PushDemo.Services;
    using Xamarin.Essentials;
    using Xamarin.Forms;
    
  6. Terapkan penanganan aktivitas untuk peristiwa IPushDemoNotificationActionServiceActionTriggered .

    void NotificationActionTriggered(object sender, PushDemoAction e)
        => ShowActionAlert(e);
    
    void ShowActionAlert(PushDemoAction action)
        => MainThread.BeginInvokeOnMainThread(()
            => MainPage?.DisplayAlert("PushDemo", $"{action} action received", "OK")
                .ContinueWith((task) => { if (task.IsFaulted) throw task.Exception; }));
    
  7. Di konstruktor Aplikasi , atasi implementasi IPushNotificationActionService menggunakan ServiceContainer dan berlangganan peristiwa IPushDemoNotificationActionServiceActionTriggered .

    public App()
    {
        InitializeComponent();
    
        ServiceContainer.Resolve<IPushDemoNotificationActionService>()
            .ActionTriggered += NotificationActionTriggered;
    
        MainPage = new MainPage();
    }
    

    Catatan

    Ini hanya untuk menunjukkan tanda terima dan penyebaran tindakan pemberitahuan push. Biasanya, ini akan ditangani secara diam-diam misalnya menavigasi ke tampilan tertentu atau menyegarkan beberapa data daripada menampilkan pemberitahuan melalui Halaman akar, MainPage dalam hal ini.

Mengonfigurasi proyek Android asli untuk pemberitahuan push

Memvalidasi nama dan izin paket

  1. Di PushDemo.Android, buka Opsi Proyek lalu Aplikasi Android dari bagian Build .

  2. Periksa apakah Nama paket cocok dengan nilai yang Anda gunakan dalam proyek Firebase ConsolePushDemo . Nama Paket dalam format com.<organization>.pushdemo.

  3. Atur Versi Android Minimum ke Android 8.0 (API level 26) dan Versi Android Target ke level API terbaru.

    Catatan

    Hanya perangkat yang menjalankan API level 26 ke atas yang didukung untuk tujuan tutorial ini namun Anda dapat memperluasnya untuk mendukung perangkat yang menjalankan versi yang lebih lama.

  4. Pastikan izin INTERNET dan READ_PHONE_STATE diaktifkan di bawah Izin yang diperlukan.

  5. Klik OK

Tambahkan basis Layanan Xamarin Google Play dan paket Xamarin.Firebase.Messaging

  1. Di PushDemo.Android, Klik Kontrol + pada folder Paket, lalu pilih Kelola Paket NuGet....

  2. Cari Xamarin.GooglePlayServices.Base (bukan Basement) dan pastikan telah diperiksa.

  3. Cari Xamarin.Firebase.Messaging dan pastikan telah diperiksa.

  4. Klik Tambahkan Paket, lalu klik Terima saat diminta untuk menerima persyaratan lisensi.

Menambahkan file JSON Google Services

  1. Kontrol + Klik proyek PushDemo.Android , lalu pilih File yang Ada... dari menu Tambahkan .

  2. Pilih file google-services.json yang Anda unduh sebelumnya saat menyiapkan proyek PushDemo di Firebase Console lalu klik Buka.

  3. Ketika diminta, pilih untuk Menyalin file ke direktori.

  4. Kontrol + Klik file google-services.json dari dalam PushDemo.Android proyek, lalu pastikan GoogleServicesJson ditetapkan sebagai Tindakan Build.

Menangani pemberitahuan push untuk Android

  1. Kontrol + Klik proyek PushDemo.Android , pilih Folder Baru dari menu Tambahkan , lalu klik Tambahkan menggunakan Layanan sebagai Nama Folder.

  2. Kontrol + Klik folder Layanan , lalu pilih File Baru... dari menu Tambahkan .

  3. PilihKelas KosongUmum>, masukkan DeviceInstallationService.cs untuk Nama, lalu klik Baru menambahkan implementasi berikut.

    using System;
    using Android.App;
    using Android.Gms.Common;
    using PushDemo.Models;
    using PushDemo.Services;
    using static Android.Provider.Settings;
    
    namespace PushDemo.Droid.Services
    {
        public class DeviceInstallationService : IDeviceInstallationService
        {
            public string Token { get; set; }
    
            public bool NotificationsSupported
                => GoogleApiAvailability.Instance
                    .IsGooglePlayServicesAvailable(Application.Context) == ConnectionResult.Success;
    
            public string GetDeviceId()
                => Secure.GetString(Application.Context.ContentResolver, Secure.AndroidId);
    
            public DeviceInstallation GetDeviceInstallation(params string[] tags)
            {
                if (!NotificationsSupported)
                    throw new Exception(GetPlayServicesError());
    
                if (string.IsNullOrWhiteSpace(Token))
                    throw new Exception("Unable to resolve token for FCM");
    
                var installation = new DeviceInstallation
                {
                    InstallationId = GetDeviceId(),
                    Platform = "fcm",
                    PushChannel = Token
                };
    
                installation.Tags.AddRange(tags);
    
                return installation;
            }
    
            string GetPlayServicesError()
            {
                int resultCode = GoogleApiAvailability.Instance.IsGooglePlayServicesAvailable(Application.Context);
    
                if (resultCode != ConnectionResult.Success)
                    return GoogleApiAvailability.Instance.IsUserResolvableError(resultCode) ?
                               GoogleApiAvailability.Instance.GetErrorString(resultCode) :
                               "This device is not supported";
    
                return "An error occurred preventing the use of push notifications";
            }
        }
    }
    

    Catatan

    Kelas ini menyediakan ID unik (menggunakan Secure.AndroidId) sebagai bagian dari payload pendaftaran hub pemberitahuan.

  4. Tambahkan Kelas Kosong lain ke folder Layanan yang disebut PushNotificationFirebaseMessagingService.cs, lalu tambahkan implementasi berikut.

    using Android.App;
    using Android.Content;
    using Firebase.Messaging;
    using PushDemo.Services;
    
    namespace PushDemo.Droid.Services
    {
        [Service]
        [IntentFilter(new[] { "com.google.firebase.MESSAGING_EVENT" })]
        public class PushNotificationFirebaseMessagingService : FirebaseMessagingService
        {
            IPushDemoNotificationActionService _notificationActionService;
            INotificationRegistrationService _notificationRegistrationService;
            IDeviceInstallationService _deviceInstallationService;
    
            IPushDemoNotificationActionService NotificationActionService
                => _notificationActionService ??
                    (_notificationActionService =
                    ServiceContainer.Resolve<IPushDemoNotificationActionService>());
    
            INotificationRegistrationService NotificationRegistrationService
                => _notificationRegistrationService ??
                    (_notificationRegistrationService =
                    ServiceContainer.Resolve<INotificationRegistrationService>());
    
            IDeviceInstallationService DeviceInstallationService
                => _deviceInstallationService ??
                    (_deviceInstallationService =
                    ServiceContainer.Resolve<IDeviceInstallationService>());
    
            public override void OnNewToken(string token)
            {
                DeviceInstallationService.Token = token;
    
                NotificationRegistrationService.RefreshRegistrationAsync()
                    .ContinueWith((task) => { if (task.IsFaulted) throw task.Exception; });
            }
    
            public override void OnMessageReceived(RemoteMessage message)
            {
                if(message.Data.TryGetValue("action", out var messageAction))
                    NotificationActionService.TriggerAction(messageAction);
            }
        }
    }
    
  5. Di MainActivity.cs, pastikan namespace berikut telah ditambahkan ke bagian atas file.

    using System;
    using Android.App;
    using Android.Content;
    using Android.Content.PM;
    using Android.OS;
    using Android.Runtime;
    using Firebase.Iid;
    using PushDemo.Droid.Services;
    using PushDemo.Services;
    
  6. Di MainActivity.cs, atur LaunchMode ke SingleTop sehingga MainActivity tidak akan dibuat lagi saat dibuka.

    [Activity(
        Label = "PushDemo",
        LaunchMode = LaunchMode.SingleTop,
        Icon = "@mipmap/icon",
        Theme = "@style/MainTheme",
        MainLauncher = true,
        ConfigurationChanges = ConfigChanges.ScreenSize | ConfigChanges.Orientation)]
    
  7. Tambahkan properti privat dan bidang dukungan yang sesuai untuk menyimpan referensi ke implementasi IPushNotificationActionService dan IDeviceInstallationService .

    IPushDemoNotificationActionService _notificationActionService;
    IDeviceInstallationService _deviceInstallationService;
    
    IPushDemoNotificationActionService NotificationActionService
        => _notificationActionService ??
            (_notificationActionService =
            ServiceContainer.Resolve<IPushDemoNotificationActionService>());
    
    IDeviceInstallationService DeviceInstallationService
        => _deviceInstallationService ??
            (_deviceInstallationService =
            ServiceContainer.Resolve<IDeviceInstallationService>());
    
  8. Terapkan antarmuka IOnSuccessListener untuk mengambil dan menyimpan token Firebase .

    public class MainActivity : global::Xamarin.Forms.Platform.Android.FormsAppCompatActivity, Android.Gms.Tasks.IOnSuccessListener
    {
        ...
    
        public void OnSuccess(Java.Lang.Object result)
            => DeviceInstallationService.Token =
                result.Class.GetMethod("getToken").Invoke(result).ToString();
    }
    
  9. Tambahkan metode baru yang disebut ProcessNotificationActions yang akan memeriksa apakah Niat tertentu memiliki nilai tambahan bernama tindakan. Secara kondisional memicu tindakan tersebut menggunakan implementasi IPushDemoNotificationActionService .

    void ProcessNotificationActions(Intent intent)
    {
        try
        {
            if (intent?.HasExtra("action") == true)
            {
                var action = intent.GetStringExtra("action");
    
                if (!string.IsNullOrEmpty(action))
                    NotificationActionService.TriggerAction(action);
            }
        }
        catch (Exception ex)
        {
            System.Diagnostics.Debug.WriteLine(ex.Message);
        }
    }
    
  10. Ambil alih metode OnNewIntent untuk memanggil metode ProcessNotificationActions .

    protected override void OnNewIntent(Intent intent)
    {
        base.OnNewIntent(intent);
        ProcessNotificationActions(intent);
    }
    

    Catatan

    Karena LaunchMode untuk Aktivitas diatur ke SingleTop, Niat akan dikirim ke instans Aktivitas yang ada melalui metode OnNewIntent daripada metode OnCreate sehingga Anda harus menangani niat masuk dalam metode OnCreate dan OnNewIntent .

  11. Perbarui metode OnCreate untuk memanggil Bootstrap.Begin tepat setelah panggilan untuk base.OnCreate meneruskan implementasi khusus platform IDeviceInstallationService.

    Bootstrap.Begin(() => new DeviceInstallationService());
    
  12. Dalam metode yang sama, panggil GetInstanceId secara kondisional pada instans FirebaseApp , tepat setelah panggilan ke Bootstrap.Begin, menambahkan MainActivity sebagai IOnSuccessListener.

    if (DeviceInstallationService.NotificationsSupported)
    {
        FirebaseInstanceId.GetInstance(Firebase.FirebaseApp.Instance)
            .GetInstanceId()
            .AddOnSuccessListener(this);
    }
    
  13. Masih di OnCreate, panggil ProcessNotificationActions segera setelah panggilan untuk LoadApplication meneruskan Niat saat ini.

    ...
    
    LoadApplication(new App());
    
    ProcessNotificationActions(Intent);
    

Catatan

Anda harus mendaftarkan ulang aplikasi setiap kali menjalankannya dan menghentikannya dari sesi debug untuk terus menerima pemberitahuan push.

Mengonfigurasi proyek iOS asli untuk pemberitahuan push

Mengonfigurasi Info.plist dan Entitlements.plist

  1. Pastikan Anda telah masuk ke Akun Pengembang Apple anda di Preferensi Visual Studio>...>Penerbitan>Akun Pengembang Apple dan Sertifikat dan Profil Provisi yang sesuai telah diunduh. Anda seharusnya membuat aset ini sebagai bagian dari langkah-langkah sebelumnya.

  2. Di PushDemo.iOS, buka Info.plist dan pastikan bahwa BundleIdentifier cocok dengan nilai yang digunakan untuk profil provisi masing-masing di Portal Pengembang Apple. BundleIdentifier dalam format com.<organization>.PushDemo.

  3. Dalam file yang sama, atur Versi sistem minimum ke 13.0.

    Catatan

    Hanya perangkat yang menjalankan iOS 13.0 ke atas yang didukung untuk tujuan tutorial ini namun Anda dapat memperluasnya untuk mendukung perangkat yang menjalankan versi yang lebih lama.

  4. Buka Opsi Proyek untuk PushDemo.iOS (klik dua kali pada proyek).

  5. Di Opsi Proyek, di bawah Buat > Penandatanganan Bundel iOS, pastikan akun Pengembang Anda dipilih di bawah Tim. Kemudian, pastikan "Kelola penandatanganan secara otomatis" dipilih dan Sertifikat Penandatanganan dan Profil Provisi Anda dipilih secara otomatis.

    Catatan

    Jika Sertifikat Penandatanganan dan Profil Provisi Anda belum dipilih secara otomatis, pilih Provisi Manual, lalu klik Opsi Penandatanganan Bundel. Pastikan Bahwa Tim Anda dipilih untuk Identitas Penandatanganan dan profil provisi khusus PushDemo Anda dipilih untuk Profil Provisi untuk konfigurasi Debug dan Rilis yang memastikan bahwa iPhone dipilih untuk Platform dalam kedua kasus.

  6. Di PushDemo.iOS, buka Entitlements.plist dan pastikan bahwa Aktifkan Pemberitahuan Push dicentang saat dilihat di tab Pemberian Hak . Kemudian, pastikan pengaturan Lingkungan APS diatur ke pengembangan saat dilihat di tab Sumber .

Menangani pemberitahuan push untuk iOS

  1. Kontrol + Klik proyek PushDemo.iOS , pilih Folder Baru dari menu Tambahkan , lalu klik Tambahkan menggunakan Layanan sebagai Nama Folder.

  2. Kontrol + Klik folder Layanan , lalu pilih File Baru... dari menu Tambahkan .

  3. PilihKelas KosongUmum>, masukkan DeviceInstallationService.cs untuk Nama, lalu klik Baru menambahkan implementasi berikut.

    using System;
    using PushDemo.Models;
    using PushDemo.Services;
    using UIKit;
    
    namespace PushDemo.iOS.Services
    {
        public class DeviceInstallationService : IDeviceInstallationService
        {
            const int SupportedVersionMajor = 13;
            const int SupportedVersionMinor = 0;
    
            public string Token { get; set; }
    
            public bool NotificationsSupported
                => UIDevice.CurrentDevice.CheckSystemVersion(SupportedVersionMajor, SupportedVersionMinor);
    
            public string GetDeviceId()
                => UIDevice.CurrentDevice.IdentifierForVendor.ToString();
    
            public DeviceInstallation GetDeviceInstallation(params string[] tags)
            {
                if (!NotificationsSupported)
                    throw new Exception(GetNotificationsSupportError());
    
                if (string.IsNullOrWhiteSpace(Token))
                    throw new Exception("Unable to resolve token for APNS");
    
                var installation = new DeviceInstallation
                {
                    InstallationId = GetDeviceId(),
                    Platform = "apns",
                    PushChannel = Token
                };
    
                installation.Tags.AddRange(tags);
    
                return installation;
            }
    
            string GetNotificationsSupportError()
            {
                if (!NotificationsSupported)
                    return $"This app only supports notifications on iOS {SupportedVersionMajor}.{SupportedVersionMinor} and above. You are running {UIDevice.CurrentDevice.SystemVersion}.";
    
                if (Token == null)
                    return $"This app can support notifications but you must enable this in your settings.";
    
    
                return "An error occurred preventing the use of push notifications";
            }
        }
    }
    

    Catatan

    Kelas ini menyediakan ID unik (menggunakan nilai UIDevice.IdentifierForVendor ) dan payload pendaftaran hub pemberitahuan.

  4. Tambahkan folder baru ke proyek PushDemo.iOS yang disebut Ekstensi lalu tambahkan Kelas Kosong ke folder yang disebut NSDataExtensions.cs dengan implementasi berikut.

    using System.Text;
    using Foundation;
    
    namespace PushDemo.iOS.Extensions
    {
        internal static class NSDataExtensions
        {
            internal static string ToHexString(this NSData data)
            {
                var bytes = data.ToArray();
    
                if (bytes == null)
                    return null;
    
                StringBuilder sb = new StringBuilder(bytes.Length * 2);
    
                foreach (byte b in bytes)
                    sb.AppendFormat("{0:x2}", b);
    
                return sb.ToString().ToUpperInvariant();
            }
        }
    }
    
  5. Di AppDelegate.cs, pastikan namespace berikut telah ditambahkan ke bagian atas file.

    using System;
    using System.Diagnostics;
    using System.Threading.Tasks;
    using Foundation;
    using PushDemo.iOS.Extensions;
    using PushDemo.iOS.Services;
    using PushDemo.Services;
    using UIKit;
    using UserNotifications;
    using Xamarin.Essentials;
    
  6. Tambahkan properti privat dan bidang dukungan masing-masing untuk menyimpan referensi ke implementasi IPushDemoNotificationActionService, INotificationRegistrationService, dan IDeviceInstallationService .

    IPushDemoNotificationActionService _notificationActionService;
    INotificationRegistrationService _notificationRegistrationService;
    IDeviceInstallationService _deviceInstallationService;
    
    IPushDemoNotificationActionService NotificationActionService
        => _notificationActionService ??
            (_notificationActionService =
            ServiceContainer.Resolve<IPushDemoNotificationActionService>());
    
    INotificationRegistrationService NotificationRegistrationService
        => _notificationRegistrationService ??
            (_notificationRegistrationService =
            ServiceContainer.Resolve<INotificationRegistrationService>());
    
    IDeviceInstallationService DeviceInstallationService
        => _deviceInstallationService ??
            (_deviceInstallationService =
            ServiceContainer.Resolve<IDeviceInstallationService>());
    
  7. Tambahkan metode RegisterForRemoteNotifications untuk mendaftarkan pengaturan pemberitahuan pengguna lalu untuk pemberitahuan jarak jauh dengan APNS.

    void RegisterForRemoteNotifications()
    {
        MainThread.BeginInvokeOnMainThread(() =>
        {
            var pushSettings = UIUserNotificationSettings.GetSettingsForTypes(
                UIUserNotificationType.Alert |
                UIUserNotificationType.Badge |
                UIUserNotificationType.Sound,
                new NSSet());
    
            UIApplication.SharedApplication.RegisterUserNotificationSettings(pushSettings);
            UIApplication.SharedApplication.RegisterForRemoteNotifications();
        });
    }
    
  8. Tambahkan metode CompleteRegistrationAsync untuk mengatur IDeviceInstallationService.Token nilai properti. Refresh pendaftaran dan cache token perangkat jika telah diperbarui sejak terakhir disimpan.

    Task CompleteRegistrationAsync(NSData deviceToken)
    {
        DeviceInstallationService.Token = deviceToken.ToHexString();
        return NotificationRegistrationService.RefreshRegistrationAsync();
    }
    
  9. Tambahkan metode ProcessNotificationActions untuk memproses data pemberitahuan NSDictionary dan memanggil NotificationActionService.TriggerAction secara kondisional.

    void ProcessNotificationActions(NSDictionary userInfo)
    {
        if (userInfo == null)
            return;
    
        try
        {
            var actionValue = userInfo.ObjectForKey(new NSString("action")) as NSString;
    
            if (!string.IsNullOrWhiteSpace(actionValue?.Description))
                NotificationActionService.TriggerAction(actionValue.Description);
        }
        catch (Exception ex)
        {
            Debug.WriteLine(ex.Message);
        }
    }
    
  10. Ambil alih metode RegisteredForRemoteNotifications yang meneruskan argumen deviceToken ke metode CompleteRegistrationAsync .

    public override void RegisteredForRemoteNotifications(
        UIApplication application,
        NSData deviceToken)
        => CompleteRegistrationAsync(deviceToken).ContinueWith((task)
            => { if (task.IsFaulted) throw task.Exception; });
    
  11. Ambil alih metode ReceivedRemoteNotification yang meneruskan argumen userInfo ke metode ProcessNotificationActions .

    public override void ReceivedRemoteNotification(
        UIApplication application,
        NSDictionary userInfo)
        => ProcessNotificationActions(userInfo);
    
  12. Ambil alih metode FailedToRegisterForRemoteNotifications untuk mencatat kesalahan.

    public override void FailedToRegisterForRemoteNotifications(
        UIApplication application,
        NSError error)
        => Debug.WriteLine(error.Description);
    

    Catatan

    Ini sangat banyak tempat penampung. Anda akan ingin menerapkan pencatatan dan penanganan kesalahan yang tepat untuk skenario produksi.

  13. Perbarui metode FinishedLaunching untuk memanggil Bootstrap.Begin tepat setelah panggilan untuk Forms.Init meneruskan implementasi khusus platform IDeviceInstallationService.

    Bootstrap.Begin(() => new DeviceInstallationService());
    
  14. Dalam metode yang sama, permintaan otorisasi secara kondisional dan daftar untuk pemberitahuan jarak jauh segera setelah Bootstrap.Begin.

    if (DeviceInstallationService.NotificationsSupported)
    {
        UNUserNotificationCenter.Current.RequestAuthorization(
                UNAuthorizationOptions.Alert |
                UNAuthorizationOptions.Badge |
                UNAuthorizationOptions.Sound,
                (approvalGranted, error) =>
                {
                    if (approvalGranted && error == null)
                        RegisterForRemoteNotifications();
                });
    }
    
  15. Masih di FinishedLaunching, panggil ProcessNotificationActions segera setelah panggilan ke LoadApplication jika argumen opsi berisi UIApplication.LaunchOptionsRemoteNotificationKey melewati objek userInfo yang dihasilkan.

    using (var userInfo = options?.ObjectForKey(
        UIApplication.LaunchOptionsRemoteNotificationKey) as NSDictionary)
            ProcessNotificationActions(userInfo);
    

Menguji solusi

Anda sekarang dapat menguji pengiriman pemberitahuan melalui layanan backend.

Mengirim pemberitahuan pengujian

  1. Buka tab baru di Postman.

  2. Atur permintaan ke POST, dan masukkan alamat berikut:

    https://<app_name>.azurewebsites.net/api/notifications/requests
    
  3. Jika Anda memilih untuk menyelesaikan klien Autentikasi menggunakan bagian Kunci API , pastikan untuk mengonfigurasi header permintaan untuk menyertakan nilai apikey Anda.

    Kunci Nilai
    apikey <your_api_key>
  4. Pilih opsi mentah untuk Isi, lalu pilih JSON dari daftar opsi format, lalu sertakan beberapa konten JSON tempat penampung:

    {
        "text": "Message from Postman!",
        "action": "action_a"
    }
    
  5. Pilih tombol Kode , yang berada di bawah tombol Simpan di kanan atas jendela. Permintaan akan terlihat mirip dengan contoh berikut saat ditampilkan untuk HTML (tergantung pada apakah Anda menyertakan header apikey ):

    POST /api/notifications/requests HTTP/1.1
    Host: https://<app_name>.azurewebsites.net
    apikey: <your_api_key>
    Content-Type: application/json
    
    {
        "text": "Message from backend service",
        "action": "action_a"
    }
    
  6. Jalankan aplikasi PushDemo pada satu atau kedua platform target (Android dan iOS).

    Catatan

    Jika Anda menguji di Android , pastikan Anda tidak berjalan di Debug, atau jika aplikasi telah disebarkan dengan menjalankan aplikasi, tutup paksa aplikasi dan mulai lagi dari peluncur.

  7. Di aplikasi PushDemo , ketuk tombol Daftar .

  8. Kembali ke Postman, tutup jendela Hasilkan Cuplikan Kode (jika Anda belum melakukannya) lalu klik tombol Kirim .

  9. Validasi bahwa Anda mendapatkan respons 200 OK di Postman dan pemberitahuan muncul di aplikasi yang menampilkan tindakan ActionA yang diterima.

  10. Tutup aplikasi PushDemo , lalu klik tombol Kirim lagi di Postman.

  11. Validasi bahwa Anda mendapatkan respons 200 OK di Postman lagi. Validasi bahwa pemberitahuan muncul di area pemberitahuan untuk aplikasi PushDemo dengan pesan yang benar.

  12. Ketuk pemberitahuan untuk mengonfirmasi bahwa ia membuka aplikasi dan menampilkan pemberitahuan tindakan ActionA yang diterima .

  13. Kembali ke Postman, ubah isi permintaan sebelumnya untuk mengirim pemberitahuan senyap yang menentukan action_b alih-alih action_a untuk nilai tindakan .

    {
        "action": "action_b",
        "silent": true
    }
    
  14. Dengan aplikasi masih terbuka, klik tombol Kirim di Postman.

  15. Validasi bahwa Anda mendapatkan respons 200 OK di Postman dan pemberitahuan muncul di aplikasi yang menampilkan tindakan ActionB yang diterima alih-alih tindakan ActionA diterima.

  16. Tutup aplikasi PushDemo , lalu klik tombol Kirim lagi di Postman.

  17. Validasi bahwa Anda mendapatkan respons 200 OK di Postman dan pemberitahuan senyap tidak muncul di area pemberitahuan.

Pemecahan masalah

Tidak ada respons dari layanan backend

Saat menguji secara lokal, pastikan bahwa layanan backend berjalan dan menggunakan port yang benar.

Jika pengujian terhadap Aplikasi Azure API, periksa layanan sedang berjalan dan telah disebarkan dan telah dimulai tanpa kesalahan.

Pastikan untuk memeriksa bahwa Anda telah menentukan alamat dasar dengan benar di Postman atau di konfigurasi aplikasi seluler saat menguji melalui klien. Alamat dasar harus secara indikatif atau https://<api_name>.azurewebsites.net/https://localhost:5001/ saat menguji secara lokal.

Tidak menerima pemberitahuan di Android setelah memulai atau menghentikan sesi debug

Pastikan Anda mendaftar lagi setelah memulai atau menghentikan sesi debug. Debugger akan menyebabkan token Firebase baru dibuat. Penginstalan hub pemberitahuan juga harus diperbarui.

Menerima kode status 401 dari layanan backend

Validasi bahwa Anda mengatur header permintaan apikey dan nilai ini cocok dengan yang telah Anda konfigurasi untuk layanan backend.

Jika Anda menerima kesalahan ini saat menguji secara lokal, pastikan nilai kunci yang Anda tentukan dalam konfigurasi klien, cocok dengan nilai pengaturan pengguna Authentication:ApiKey yang digunakan oleh API.

Jika Anda menguji dengan Aplikasi API, pastikan nilai kunci dalam file konfigurasi klien cocok dengan pengaturan aplikasi Authentication:ApiKey yang Anda gunakan di Aplikasi API.

Catatan

Jika Anda telah membuat atau mengubah pengaturan ini setelah Anda menyebarkan layanan backend, maka Anda harus memulai ulang layanan agar berlaku.

Jika Anda memilih untuk tidak menyelesaikan klien Autentikasi menggunakan bagian Kunci API , pastikan Anda tidak menerapkan atribut Otorisasi ke kelas NotificationsController .

Menerima kode status 404 dari layanan backend

Validasi bahwa titik akhir dan metode permintaan HTTP sudah benar. Misalnya, titik akhir harus secara indikatif:

  • [PUT]https://<api_name>.azurewebsites.net/api/notifications/installations
  • [HAPUS]https://<api_name>.azurewebsites.net/api/notifications/installations/<installation_id>
  • [POST]https://<api_name>.azurewebsites.net/api/notifications/requests

Atau saat menguji secara lokal:

  • [PUT]https://localhost:5001/api/notifications/installations
  • [HAPUS]https://localhost:5001/api/notifications/installations/<installation_id>
  • [POST]https://localhost:5001/api/notifications/requests

Saat menentukan alamat dasar di aplikasi klien, pastikan alamat tersebut berakhir dengan /. Alamat dasar harus secara indikatif atau https://<api_name>.azurewebsites.net/https://localhost:5001/ saat menguji secara lokal.

Tidak dapat mendaftar dan pesan kesalahan hub pemberitahuan ditampilkan

Verifikasi bahwa perangkat pengujian memiliki konektivitas jaringan. Kemudian, tentukan kode status respons Http dengan mengatur titik henti untuk memeriksa nilai properti StatusCode di HttpResponse.

Tinjau saran pemecahan masalah sebelumnya jika berlaku berdasarkan kode status.

Atur titik henti pada baris yang mengembalikan kode status khusus ini untuk API masing-masing. Kemudian coba panggil layanan backend saat men-debug secara lokal.

Validasi layanan backend berfungsi seperti yang diharapkan melalui Postman menggunakan payload yang sesuai. Gunakan payload aktual yang dibuat oleh kode klien untuk platform yang dimaksud.

Tinjau bagian konfigurasi khusus platform untuk memastikan bahwa tidak ada langkah yang terlewatkan. Periksa apakah nilai yang sesuai sedang diselesaikan untuk installation id variabel dan token untuk platform yang sesuai.

Tidak dapat mengatasi ID untuk pesan kesalahan perangkat ditampilkan

Tinjau bagian konfigurasi khusus platform untuk memastikan bahwa tidak ada langkah yang terlewatkan.

Langkah berikutnya

Anda sekarang harus memiliki aplikasi Xamarin.Forms dasar yang terhubung ke hub pemberitahuan melalui layanan backend dan dapat mengirim dan menerima pemberitahuan.

Anda mungkin perlu menyesuaikan contoh yang digunakan dalam tutorial ini agar sesuai dengan skenario Anda sendiri. Menerapkan penanganan kesalahan yang lebih kuat, logika coba lagi, dan pengelogan juga disarankan.

Visual Studio App Center dapat dengan cepat dimasukkan ke dalam aplikasi seluler yang menyediakan analitik dan diagnostik untuk membantu dalam pemecahan masalah.