Tutorial: Mengirim pemberitahuan push ke aplikasi Flutter menggunakan Azure Notification Hubs melalui layanan backend
Dalam tutorial ini, Anda menggunakan Azure Notification Hubs untuk mendorong pemberitahuan ke aplikasi Flutter 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.
- Toolkit Flutter (bersama dengan prasyaratnya).
- Visual Studio Code dengan plugin Flutter dan Dart terinstal.
- CocoaPods diinstal untuk mengelola dependensi pustaka.
- 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:
- Akun Pengembang Apple aktif.
- Perangkat iOS fisik yang didaftarkan ke akun pengembang Anda(menjalankan iOS 13.0 ke atas).
- Sertifikat pengembangan.p12 yang diinstal di rantai kunci Anda memungkinkan Anda menjalankan aplikasi di perangkat fisik.
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 keakraban dengan aspek-aspek berikut.
- Portal Pengembang Apple.
- ASP.NET Core.
- Google Firebase Console.
- Microsoft Azure dan Kirim pemberitahuan push ke aplikasi iOS menggunakan Azure Notification Hubs.
- Flutter dan Dart untuk pengembangan lintas platform.
- Kotlin dan Swift untuk pengembangan asli Android dan iOS.
Langkah-langkah yang disediakan khusus untuk macOS. Dimungkinkan untuk mengikuti Windows dengan melewatkan aspek iOS .
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
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.
Setelah membuat proyek, pilih Tambahkan Firebase ke aplikasi Android Anda.
Pada halaman Tambahkan Firebase ke aplikasi Android Anda , ikuti langkah-langkah berikut.
Untuk nama paket Android, masukkan nama untuk paket Anda. Misalnya:
com.<organization_identifier>.<package_name>
.Pilih Daftarkan aplikasi.
Pilih Unduh google-services.json. Kemudian simpan file ke folder lokal untuk digunakan nanti dan pilih Berikutnya.
Pilih Berikutnya.
Pilih Lanjutkan ke konsol
Catatan
Jika tombol Lanjutkan ke konsol tidak diaktifkan, karena pemeriksaan penginstalan verifikasi , pilih Lewati langkah ini.
Di konsol Firebase, pilih roda gigi untuk proyek Anda. Lalu pilih Pengaturan Proyek.
Catatan
Jika Anda belum mengunduh file google-services.json , Anda dapat mengunduhnya di halaman ini.
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.
Mendaftarkan aplikasi iOS Anda untuk pemberitahuan push
Untuk mengirim pemberitahuan push ke app iOS, daftarkan aplikasi Anda dengan Apple, dan daftarkan juga pemberitahuan push.
Jika Anda belum mendaftarkan aplikasi, telusuri ke Portal Provisi iOS di Pusat Pengembang Apple. Masuk ke portal dengan ID Apple Anda, navigasikan ke Sertifikat, Pengidentifikasi & Profil, lalu pilih Pengidentifikasi. Klik + untuk mendaftarkan aplikasi baru.
Pada layar Daftarkan Pengidentifikasi Baru , pilih tombol radio ID Aplikasi . Lalu pilih Lanjutkan.
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.Pemberitahuan Push: Periksa opsi Pemberitahuan Push di bagian Kemampuan .
Tindakan ini menghasilkan ID Aplikasi dan permintaan yang Anda konfirmasi informasinya. Pilih Lanjutkan, lalu pilih Daftar untuk mengonfirmasi ID Aplikasi baru.
Setelah memilih Daftar, Anda akan melihat ID Aplikasi baru sebagai item baris di halaman Sertifikat, Pengidentifikasi, & Profil .
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:
Membuat sertifikat push p12 yang dapat diunggah langsung ke Notification Hub (pendekatan asli)
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 di dokumentasikan dalam autentikasi berbasis Token (HTTP/2) untuk APNS. Lebih sedikit langkah yang 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
Di Mac Anda, jalankan alat Akses Rantai Kunci. Ini dapat dibuka dari folder Utilitas atau folder Lainnya di Launchpad.
Pilih Akses Rantai Kunci, perluas Asisten Sertifikat, lalu pilih Minta Sertifikat dari Otoritas Sertifikat.
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).
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.
Masukkan nama untuk file Permintaan Penandatanganan Sertifikat (CSR) di Simpan Sebagai, pilih lokasi di Tempat, lalu pilih Simpan.
Tindakan ini menyimpan file CSR di lokasi yang dipilih. Lokasi defaultnya adalah Desktop. Ingat lokasi yang dipilih untuk file.
Kembali ke halaman Sertifikat, Pengidentifikasi, & Profil di Portal Provisi iOS, gulir ke bawah ke opsi Pemberitahuan Push yang dicentang, lalu pilih Konfigurasi untuk membuat sertifikat.
Jendela Sertifikat TLS/SSL layanan Pemberitahuan Push Apple muncul. Pilih tombol Buat Sertifikat di bawah bagian Sertifikat TLS/SSL Pengembangan .
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.
Pilih Pilih File, telusuri ke lokasi tempat Anda menyimpan file CSR, lalu klik dua kali nama sertifikat untuk memuatnya. Lalu pilih Lanjutkan.
Setelah portal membuat sertifikat, pilih tombol Unduh . Simpan sertifikat, dan ingat lokasi penyimpanannya.
Sertifikat diunduh dan disimpan ke komputer Anda di folder Unduhan Anda.
Catatan
Secara default, sertifikat pengembangan yang diunduh diberi nama aps_development.cer.
Klik dua kali aps_development.cer sertifikat push yang diunduh. Tindakan ini menginstal sertifikat baru di Rantai Kunci, seperti yang ditunjukkan pada gambar berikut:
Catatan
Meskipun nama dalam sertifikat Anda mungkin berbeda, namanya akan diawali dengan Apple Development iOS Push Services dan memiliki pengidentifikasi bundel yang sesuai yang terkait dengannya.
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.
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
Catat detail berikut:
- Awalan ID Aplikasi (ID Tim)
- ID Bundel
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.
Klik tombol + (atau tombol Buat kunci ) untuk membuat kunci baru.
Berikan nilai Nama Kunci yang sesuai, lalu centang opsi Layanan Pemberitahuan Push Apple (APNS), lalu klik Lanjutkan, diikuti dengan Daftar di layar berikutnya.
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.
Pada Kunci, klik kunci yang Anda buat (atau kunci yang ada jika Anda telah memilih untuk menggunakannya sebagai gantinya).
Catat nilai ID Kunci .
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 PRIVATE KEY-----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
Kembali ke Portal Provisi iOS, pilih Sertifikat, Pengidentifikasi & Profil, pilih Profil dari menu kiri, lalu pilih + untuk membuat profil baru. Layar Daftarkan Profil Provisi Baru muncul.
Pilih Pengembangan Aplikasi iOS di bagian Pengembangan sebagai jenis profil provisi, lalu pilih Lanjutkan.
Selanjutnya, pilih ID aplikasi yang Anda buat dari daftar drop-down ID Aplikasi , dan pilih Lanjutkan.
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.
Kembali ke halaman Sertifikat, Pengidentifikasi & Profil , pilih Profil dari menu sebelah kiri, lalu pilih + untuk membuat profil baru. Layar Daftarkan Profil Provisi Baru muncul.
Di jendela Pilih sertifikat , pilih sertifikat pengembangan yang Anda buat. Lalu pilih Lanjutkan.
Selanjutnya, pilih perangkat yang akan digunakan untuk pengujian, dan pilih Lanjutkan.
Terakhir, pilih nama untuk profil di Nama Profil Provisi, dan pilih Buat.
Saat profil provisi baru dibuat, pilih Unduh. Ingat lokasi penyimpanannya.
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.
Masuk ke Azure.
Klik Buat sumber daya, lalu cari dan pilih Notification Hub, lalu klik Buat.
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 HUB PEMBERITAHUAN
Notification Hub: Masukkan nama untuk Notification Hub
Lokasi: Pilih lokasi yang sesuai dari daftar drop-down
Tingkat Harga: Pertahankan opsi Gratis defaultCatatan
Kecuali Anda telah mencapai jumlah maksimum hub pada tingkat gratis.
Setelah Notification Hub disediakan, navigasikan ke sumber daya tersebut.
Navigasikan ke Notification Hub baru Anda.
Pilih Kebijakan Akses dari daftar (di bawah KELOLA) .
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 Mode Produksi untuk Aplikasi hanya jika Anda ingin mengirim pemberitahuan push kepada pengguna yang membeli aplikasi Anda dari toko.
OPSI 1: Menggunakan sertifikat pendorongan .p12
Pilih Sertifikat.
Pilih ikon file.
Pilih file .p12 yang Anda ekspor sebelumnya, lalu pilih Buka.
Jika perlu, tentukan kata sandi yang benar.
Pilih Mode kotak pasir .
Pilih Simpan.
OPSI 2: Menggunakan autentikasi berbasis token
Pilih Token.
Masukkan nilai berikut yang Anda peroleh sebelumnya:
- ID Kunci
- ID Bundel
- ID Tim
- Token
Pilih Sandbox.
Pilih Simpan.
Mengonfigurasi hub pemberitahuan Anda dengan informasi FCM
- Pilih Google (GCM/FCM) di bagian Pengaturan di menu sebelah kiri.
- Masukkan kunci server yang Anda catat dari Google Firebase Console.
- 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 Flutter.
Membuat proyek web
Di Visual Studio, pilih File>Solusi Baru.
Pilih .NET Core>App>ASP.NET Core>API>Berikutnya.
Dalam dialog Konfigurasikan ASP.NET Core Web API baru Anda , pilih Kerangka Kerja Target.NET Core 3.1.
Masukkan PushDemoApi untuk Nama Proyek lalu pilih Buat.
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 :
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.
Klik Ya saat diminta untuk Menginstal dan mempercayai sertifikat baru, lalu masukkan kata sandi untuk Rantai Kunci Anda.
Perluas folder Pengontrol , lalu hapus WeatherForecastController.cs.
Hapus WeatherForecast.cs.
Siapkan nilai konfigurasi lokal menggunakan alat Secret Manager. Memisahkan rahasia dari solusi memastikan bahwa rahasia tersebut tidak berakhir dalam 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 AksesCatatan
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.
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.
Kontrol + Klik proyek PushDemoApi , pilih Folder Baru dari menu Tambahkan , lalu klik Tambahkan menggunakan Autentikasi sebagai Nama Folder.
Kontrol + Klik folder Autentikasi , lalu pilih File Baru... dari menu Tambahkan .
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; } } }
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.
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.
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); }
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.
Kontrol + Klik folder Dependensi , lalu pilih Kelola Paket NuGet....
Cari Microsoft.Azure.NotificationHubs dan pastikan diperiksa.
Klik Tambahkan Paket, lalu klik Terima saat diminta untuk menerima persyaratan lisensi.
Kontrol + Klik proyek PushDemoApi , pilih Folder Baru dari menu Tambahkan , lalu klik Tambahkan menggunakan Model sebagai Nama Folder.
Kontrol + Klik folder Model , lalu pilih File Baru... dari menu Tambahkan .
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.
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>(); } }
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; } } }
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; } } }
Tambahkan folder baru ke proyek PushDemoApi yang disebut Layanan.
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); } }
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.
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
Kontrol + Klik folder Pengontrol , lalu pilih File Baru... dari menu Tambahkan .
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 .
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;
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.
Jika Anda memilih untuk menyelesaikan klien Autentikasi menggunakan bagian Kunci API , Anda juga harus menghias NotificationsController dengan atribut Otorisasi .
[Authorize]
Perbarui konstruktor untuk menerima instans terdaftar INotificationService sebagai argumen dan tetapkan ke anggota readonly.
readonly INotificationService _notificationService; public NotificationsController(INotificationService notificationService) { _notificationService = notificationService; }
Di launchSettings.json (dalam folder Properti ), ubah launchUrl dari
weatherforecast
ke api/pemberitahuan agar sesuai dengan URL yang ditentukan dalam atribut RegistrationsControllerRoute .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.
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.
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> 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.
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.
Masuk ke portal Azure.
Klik Buat sumber daya, lalu cari dan pilih Aplikasi API, lalu klik Buat.
Perbarui bidang berikut, lalu klik Buat.
Nama aplikasi:
Masukkan nama unik global untuk Aplikasi APIBerlangganan:
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 baruCatatan
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.Setelah Aplikasi API disediakan, navigasikan ke sumber daya tersebut.
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
.Pilih Konfigurasi dari daftar (di bawah Pengaturan).
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 klien Autentikasi menggunakan bagian Kunci API . Untuk skenario produksi, Anda dapat melihat opsi seperti Azure KeyVault. Ini telah ditambahkan sebagai pengaturan aplikasi untuk kesederhanaan dalam kasus ini.
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.
Ubah konfigurasi Anda dari Debug ke Rilis jika Anda belum melakukannya.
Kontrol + Klik proyek PushDemoApi , lalu pilih Terbitkan ke Azure... dari menu Terbitkan .
Ikuti alur autentikasi jika diminta untuk melakukannya. Gunakan akun yang Anda gunakan di bagian buat Aplikasi API sebelumnya.
Pilih Aplikasi API Azure App Service yang Anda buat sebelumnya dari daftar sebagai target publikasi Anda, lalu klik Terbitkan.
Setelah Anda menyelesaikan wizard, wizard 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
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 sebelumnya terbitkan layanan backend .
https://<app_name>.azurewebsites.net/api/notifications/installations
Catatan
Alamat dasar harus dalam format
https://<app_name>.azurewebsites.net/
Jika Anda memilih untuk menyelesaikan bagian Autentikasi klien menggunakan Kunci API , pastikan untuk mengonfigurasi header permintaan untuk menyertakan nilai apikey Anda.
Kunci Nilai apikey <your_api_key> Pilih opsi mentah untuk Isi, lalu pilih JSON dari daftar opsi format, lalu sertakan beberapa konten JSON tempat penampung:
{}
Klik Kirim.
Catatan
Anda harus menerima status UnprocessableEntity 422 dari layanan.
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 Flutter lintas platform
Di bagian ini, Anda membangun aplikasi seluler Flutter 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 eksekusi 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 Flutter
Buka instans baru Visual Studio Code.
Buka Palet Perintah (Perintah + Shift + P).
Pilih perintah Flutter: New Project lalu tekan Enter.
Masukkan push_demo untuk Nama Proyek lalu pilih Lokasi proyek.
Saat diminta untuk melakukannya, pilih Dapatkan Paket.
Kontrol + Klik folder kotlin (di bawah app>src>main), lalu pilih Ungkap di Finder. Kemudian, ganti nama folder anak (di bawah folder kotlin ) menjadi
com
,<your_organization>
, danpushdemo
masing-masing.Catatan
Saat menggunakan templat Visual Studio Code folder ini default ke com, misalnya, <project_name>. Dengan asumsi mobcat digunakan untuk organisasi, struktur folder harus secara indikatif muncul sebagai:
- kotlin
- Com
- mobcat
- pushdemo
- mobcat
- Com
- kotlin
Kembali ke Visual Studio Code, perbarui nilai applicationId diaplikasi>android>build.gradle ke
com.<your_organization>.pushdemo
.Catatan
Anda harus menggunakan nama organisasi Anda sendiri untuk <tempat penampung your_organization> . Misalnya, menggunakan mobcat sebagai organisasi akan menghasilkan nilai nama paketcom.mobcat.pushdemo.
Perbarui atribut paket dalam file AndroidManifest.xml, di bawahdebugsrc>, src>utama, danprofilsrc> masing-masing. Pastikan nilai cocok dengan applicationId yang Anda gunakan di langkah sebelumnya.
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.<your_organization>.pushdemo>"> ... </manifest>
android:label
Perbarui atribut dalam file AndroidManifest.xml di bawah src>main ke PushDemo. Kemudian, tambahkanandroid:allowBackup
atribut , langsung di bawahandroid:label
, atur nilainya ke false.<application android:name="io.flutter.app.FlutterApplication" android:label="PushDemo" android:allowBackup="false" android:icon="@mipmap/ic_launcher"> ... </application>
Buka file build.gradle tingkat aplikasi (aplikasi>android>build.gradle), lalu perbarui compileSdkVersion (dari bagian android) untuk menggunakan API 29. Kemudian, perbarui nilai minSdkVersion dan targetSdkVersion (dari bagian defaultConfig ), menjadi masing-masing 26 dan 29 .
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.
Kontrol + Klik folder ios , lalu pilih Buka di Xcode.
Di Xcode, klik Runner ( xcodeproj di bagian atas, bukan folder). Kemudian, pilih target Runner dan pilih tab Umum . Dengan konfigurasi Semua build dipilih, perbarui Pengidentifikasi Bundel ke
com.<your_organization>.PushDemo
.Catatan
Anda harus menggunakan nama organisasi Anda sendiri untuk <tempat penampung your_organization> . Misalnya, menggunakan mobcat sebagai organisasi akan menghasilkan nilai Pengidentifikasi Bundelcom.mobcat.PushDemo.
Klik Info.plist lalu perbarui nilai Nama bundel ke PushDemo
Tutup Xcode dan kembali ke Visual Studio Code.
Kembali ke Visual Studio Code, buka pubspec.yaml, tambahkan paket http dan flutter_secure_storageDart sebagai dependensi. Kemudian, simpan file dan klik Dapatkan Paket saat diminta untuk melakukannya.
dependencies: flutter: sdk: flutter http: ^0.12.1 flutter_secure_storage: ^3.3.3
Di Terminal, ubah direktori ke folder ios (untuk proyek Flutter Anda). Kemudian, jalankan perintah instal pod untuk menginstal pod baru (diperlukan oleh paket flutter_secure_storage ).
Kontrol + Klik folder lib , lalu pilih File Baru dari menu menggunakan main_page.dart sebagai nama file. Kemudian, tambahkan kode berikut.
import 'package:flutter/material.dart'; class MainPage extends StatefulWidget { @override _MainPageState createState() => _MainPageState(); } class _MainPageState extends State<MainPage> { @override Widget build(BuildContext context) { return Scaffold( body: SafeArea( child: Column( crossAxisAlignment: CrossAxisAlignment.stretch, children: <Widget>[], ) ) ); } }
Di main.dart, ganti kode templat dengan yang berikut ini.
import 'package:flutter/material.dart'; import 'package:push_demo/main_page.dart'; final navigatorKey = GlobalKey<NavigatorState>(); void main() => runApp(MaterialApp(home: MainPage(), navigatorKey: navigatorKey));
Di Terminal, buat dan jalankan aplikasi di setiap platform target untuk menguji aplikasi templat yang berjalan di perangkat Anda. Pastikan perangkat yang didukung tersambung.
flutter run
Menerapkan komponen lintas platform
Kontrol + Klik folder lib , lalu pilih Folder Baru dari menu menggunakan model sebagai Nama Folder.
Kontrol + Klik folder model , lalu pilih File Baru dari menu menggunakan device_installation.dart sebagai nama file. Kemudian, tambahkan kode berikut.
class DeviceInstallation { final String deviceId; final String platform; final String token; final List<String> tags; DeviceInstallation(this.deviceId, this.platform, this.token, this.tags); DeviceInstallation.fromJson(Map<String, dynamic> json) : deviceId = json['installationId'], platform = json['platform'], token = json['pushChannel'], tags = json['tags']; Map<String, dynamic> toJson() => { 'installationId': deviceId, 'platform': platform, 'pushChannel': token, 'tags': tags, }; }
Tambahkan file baru ke folder model yang disebut push_demo_action.dart yang menentukan enumerasi tindakan yang didukung dalam contoh ini.
enum PushDemoAction { actionA, actionB, }
Tambahkan folder baru ke proyek yang disebut layanan lalu tambahkan file baru ke folder yang disebut device_installation_service.dart dengan implementasi berikut.
import 'package:flutter/services.dart'; class DeviceInstallationService { static const deviceInstallation = const MethodChannel('com.<your_organization>.pushdemo/deviceinstallation'); static const String getDeviceIdChannelMethod = "getDeviceId"; static const String getDeviceTokenChannelMethod = "getDeviceToken"; static const String getDevicePlatformChannelMethod = "getDevicePlatform"; Future<String> getDeviceId() { return deviceInstallation.invokeMethod(getDeviceIdChannelMethod); } Future<String> getDeviceToken() { return deviceInstallation.invokeMethod(getDeviceTokenChannelMethod); } Future<String> getDevicePlatform() { return deviceInstallation.invokeMethod(getDevicePlatformChannelMethod); } }
Catatan
Anda harus menggunakan nama organisasi Anda sendiri untuk <tempat penampung your_organization> . Misalnya, menggunakan mobcat sebagai organisasi akan menghasilkan nama MethodChannelcom.mobcat.pushdemo/deviceinstallation.
Kelas ini merangkum bekerja dengan platform asli yang mendasarinya untuk memperoleh detail penginstalan perangkat yang diperlukan. MethodChannel memfasilitasi komunikasi asinkron dua arah dengan platform asli yang mendasar. Mitra khusus platform untuk saluran ini akan dibuat pada langkah-langkah selanjutnya.
Tambahkan file lain ke folder yang disebut notification_action_service.dart dengan implementasi berikut.
import 'package:flutter/services.dart'; import 'dart:async'; import 'package:push_demo/models/push_demo_action.dart'; class NotificationActionService { static const notificationAction = const MethodChannel('com.<your_organization>.pushdemo/notificationaction'); static const String triggerActionChannelMethod = "triggerAction"; static const String getLaunchActionChannelMethod = "getLaunchAction"; final actionMappings = { 'action_a' : PushDemoAction.actionA, 'action_b' : PushDemoAction.actionB }; final actionTriggeredController = StreamController.broadcast(); NotificationActionService() { notificationAction .setMethodCallHandler(handleNotificationActionCall); } Stream get actionTriggered => actionTriggeredController.stream; Future<void> triggerAction({action: String}) async { if (!actionMappings.containsKey(action)) { return; } actionTriggeredController.add(actionMappings[action]); } Future<void> checkLaunchAction() async { final launchAction = await notificationAction.invokeMethod(getLaunchActionChannelMethod) as String; if (launchAction != null) { triggerAction(action: launchAction); } } Future<void> handleNotificationActionCall(MethodCall call) async { switch (call.method) { case triggerActionChannelMethod: return triggerAction(action: call.arguments as String); default: throw MissingPluginException(); break; } } }
Catatan
Ini digunakan sebagai mekanisme sederhana untuk mempusatkan penanganan tindakan pemberitahuan sehingga dapat ditangani dengan cara lintas platform menggunakan enumerasi yang ditik dengan kuat. Layanan ini memungkinkan platform asli yang mendasar untuk memicu tindakan, ketika satu ditentukan dalam payload pemberitahuan. Ini juga memungkinkan kode umum untuk secara retrospektif memeriksa apakah tindakan ditentukan selama peluncuran aplikasi setelah Flutter siap untuk memprosesnya. Misalnya, saat aplikasi diluncurkan dengan mengetuk pemberitahuan dari pusat pemberitahuan.
Tambahkan file baru ke folder layanan yang disebut notification_registration_service.dart dengan implementasi berikut.
import 'dart:convert'; import 'package:flutter/services.dart'; import 'package:http/http.dart' as http; import 'package:push_demo/services/device_installation_service.dart'; import 'package:push_demo/models/device_installation.dart'; import 'package:flutter_secure_storage/flutter_secure_storage.dart'; class NotificationRegistrationService { static const notificationRegistration = const MethodChannel('com.<your_organization>.pushdemo/notificationregistration'); static const String refreshRegistrationChannelMethod = "refreshRegistration"; static const String installationsEndpoint = "api/notifications/installations"; static const String cachedDeviceTokenKey = "cached_device_token"; static const String cachedTagsKey = "cached_tags"; final deviceInstallationService = DeviceInstallationService(); final secureStorage = FlutterSecureStorage(); String baseApiUrl; String apikey; NotificationRegistrationService(this.baseApiUrl, this.apikey) { notificationRegistration .setMethodCallHandler(handleNotificationRegistrationCall); } String get installationsUrl => "$baseApiUrl$installationsEndpoint"; Future<void> deregisterDevice() async { final cachedToken = await secureStorage.read(key: cachedDeviceTokenKey); final serializedTags = await secureStorage.read(key: cachedTagsKey); if (cachedToken == null || serializedTags == null) { return; } var deviceId = await deviceInstallationService.getDeviceId(); if (deviceId.isEmpty) { throw "Unable to resolve an ID for the device."; } var response = await http .delete("$installationsUrl/$deviceId", headers: {"apikey": apikey}); if (response.statusCode != 200) { throw "Deregister request failed: ${response.reasonPhrase}"; } await secureStorage.delete(key: cachedDeviceTokenKey); await secureStorage.delete(key: cachedTagsKey); } Future<void> registerDevice(List<String> tags) async { try { final deviceId = await deviceInstallationService.getDeviceId(); final platform = await deviceInstallationService.getDevicePlatform(); final token = await deviceInstallationService.getDeviceToken(); final deviceInstallation = DeviceInstallation(deviceId, platform, token, tags); final response = await http.put(installationsUrl, body: jsonEncode(deviceInstallation), headers: {"apikey": apikey, "Content-Type": "application/json"}); if (response.statusCode != 200) { throw "Register request failed: ${response.reasonPhrase}"; } final serializedTags = jsonEncode(tags); await secureStorage.write(key: cachedDeviceTokenKey, value: token); await secureStorage.write(key: cachedTagsKey, value: serializedTags); } on PlatformException catch (e) { throw e.message; } catch (e) { throw "Unable to register device: $e"; } } Future<void> refreshRegistration() async { final currentToken = await deviceInstallationService.getDeviceToken(); final cachedToken = await secureStorage.read(key: cachedDeviceTokenKey); final serializedTags = await secureStorage.read(key: cachedTagsKey); if (currentToken == null || cachedToken == null || serializedTags == null || currentToken == cachedToken) { return; } final tags = jsonDecode(serializedTags); return registerDevice(tags); } Future<void> handleNotificationRegistrationCall(MethodCall call) async { switch (call.method) { case refreshRegistrationChannelMethod: return refreshRegistration(); default: throw MissingPluginException(); break; } } }
Catatan
Kelas ini merangkum penggunaan DeviceInstallationService dan permintaan ke layanan backend untuk melakukan tindakan pendaftaran, deregister, dan refresh pendaftaran yang diperlukan. Argumen apiKey hanya diperlukan jika Anda memilih untuk menyelesaikan klien Autentikasi menggunakan bagian Kunci API .
Tambahkan file baru ke folder lib yang disebut config.dart dengan implementasi berikut.
class Config { static String apiKey = "API_KEY"; static String backendServiceEndpoint = "BACKEND_SERVICE_ENDPOINT"; }
Catatan
Ini digunakan sebagai cara sederhana untuk menentukan rahasia aplikasi. 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/
. Anggota apiKey hanya diperlukan jika Anda memilih untuk menyelesaikan klien Autentikasi menggunakan bagian Kunci API .Pastikan untuk menambahkan ini ke file gitignore Anda untuk menghindari penerapan rahasia ini ke kontrol sumber.
Menerapkan UI lintas platform
Di main_page.dart, ganti fungsi build dengan yang berikut.
@override Widget build(BuildContext context) { return Scaffold( body: Padding( padding: const EdgeInsets.symmetric(horizontal: 20.0, vertical: 40.0), child: Column( mainAxisAlignment: MainAxisAlignment.end, crossAxisAlignment: CrossAxisAlignment.stretch, children: <Widget>[ FlatButton( child: Text("Register"), onPressed: registerButtonClicked, ), FlatButton( child: Text("Deregister"), onPressed: deregisterButtonClicked, ), ], ), ), ); }
Tambahkan impor yang disyaratkan ke bagian atas file main_page.dart .
import 'package:push_demo/services/notification_registration_service.dart'; import 'config.dart';
Tambahkan bidang ke kelas _MainPageState untuk menyimpan referensi ke NotificationRegistrationService.
final notificationRegistrationService = NotificationRegistrationService(Config.backendServiceEndpoint, Config.apiKey);
Di kelas _MainPageState , terapkan penanganan aktivitas untuk tombol Daftar dan Batalkan pendaftaranpada peristiwa yang ditekan . Panggil metode Register/Deregister yang sesuai lalu tampilkan pemberitahuan untuk menunjukkan hasilnya.
void registerButtonClicked() async { try { await notificationRegistrationService.registerDevice(List<String>()); await showAlert(message: "Device registered"); } catch (e) { await showAlert(message: e); } } void deregisterButtonClicked() async { try { await notificationRegistrationService.deregisterDevice(); await showAlert(message: "Device deregistered"); } catch (e) { await showAlert(message: e); } } Future<void> showAlert({ message: String }) async { return showDialog<void>( context: context, barrierDismissible: false, builder: (BuildContext context) { return AlertDialog( title: Text('PushDemo'), content: SingleChildScrollView( child: ListBody( children: <Widget>[ Text(message), ], ), ), actions: <Widget>[ FlatButton( child: Text('OK'), onPressed: () { Navigator.of(context).pop(); }, ), ], ); }, ); }
Sekarang di main.dart, pastikan impor berikut ada di bagian atas file.
import 'package:flutter/material.dart'; import 'package:push_demo/models/push_demo_action.dart'; import 'package:push_demo/services/notification_action_service.dart'; import 'package:push_demo/main_page.dart';
Deklarasikan variabel untuk menyimpan referensi ke instans NotificationActionService dan menginisialisasinya.
final notificationActionService = NotificationActionService();
Tambahkan fungsi untuk menangani tampilan pemberitahuan saat tindakan dipicu.
void notificationActionTriggered(PushDemoAction action) { showActionAlert(message: "${action.toString().split(".")[1]} action received"); } Future<void> showActionAlert({ message: String }) async { return showDialog<void>( context: navigatorKey.currentState.overlay.context, barrierDismissible: false, builder: (BuildContext context) { return AlertDialog( title: Text('PushDemo'), content: SingleChildScrollView( child: ListBody( children: <Widget>[ Text(message), ], ), ), actions: <Widget>[ FlatButton( child: Text('OK'), onPressed: () { Navigator.of(context).pop(); }, ), ], ); }, ); }
Perbarui fungsi utama untuk mengamati streaming NotificationActionServiceactionTriggered dan periksa tindakan apa pun yang diambil selama peluncuran aplikasi.
void main() async { runApp(MaterialApp(home: MainPage(), navigatorKey: navigatorKey,)); notificationActionService.actionTriggered.listen((event) { notificationActionTriggered(event as PushDemoAction); }); await notificationActionService.checkLaunchAction(); }
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 me-refresh beberapa data daripada menampilkan pemberitahuan dalam kasus ini.
Mengonfigurasi proyek Android asli untuk pemberitahuan push
Menambahkan file JSON Google Services
Kontrol + Klik folder android , lalu pilih Buka di Android Studio. Kemudian, beralihlah ke tampilan Proyek (jika belum).
Temukan file google-services.json yang Anda unduh sebelumnya saat menyiapkan proyek PushDemo di Firebase Console. Kemudian, seret ke direktori akar modul aplikasi (aplikasiandroid android>>).
Mengonfigurasi pengaturan dan izin build
Alihkan tampilan Project ke Android.
Buka AndroidManifest.xml, lalu tambahkan izin INTERNET dan READ_PHONE_STATE setelah elemen aplikasi sebelum tag penutup .
<manifest> <application>...</application> <uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.READ_PHONE_STATE" /> </manifest>
Menambahkan Firebase SDK
Di Android Studio, buka file build.gradle tingkat proyek (Gradle Scripts>build.gradle (Project: android)). dan pastikan Anda memiliki classpath 'com.google.gms:google-services' di simpul
buildscript
>dependensi .buildscript { repositories { // Check that you have the following line (if not, add it): google() // Google's Maven repository } dependencies { // ... // Add the following line: classpath 'com.google.gms:google-services:4.3.3' // Google Services plugin } } allprojects { // ... repositories { // Check that you have the following line (if not, add it): google() // Google's Maven repository // ... } }
Catatan
Pastikan Anda mereferensikan versi terbaru sesuai instruksi yang disediakan di Firebase Console saat Membuat Proyek Android.
Dalam file build.gradle tingkat aplikasi (Gradle Scripts>build.gradle (Module: app)), terapkan plugin Google Services Gradle. Terapkan plugin tepat di atas simpul android .
// ... // Add the following line: apply plugin: 'com.google.gms.google-services' // Google Services plugin android { // ... }
Dalam file yang sama, di simpul dependensi , tambahkan dependensi untuk pustaka Android Cloud Messaging .
dependencies { // ... implementation 'com.google.firebase:firebase-messaging:20.2.0' }
Catatan
Pastikan Anda mereferensikan versi terbaru sesuai dokumentasi klien Cloud Messaging Android.
Simpan perubahan, lalu klik tombol Sinkronkan Sekarang (dari prompt toolbar) atau Sinkronkan Project dengan File Gradle.
Menangani pemberitahuan push untuk Android
Di Android Studio, Klik Pada + folder paket com.your_organization.pushdemo<> (app>src>main>kotlin), pilih Paket dari menu Baru. Masukkan layanan sebagai nama, lalu tekan Return.
Kontrol + Klik folder layanan , pilih File/Kelas Kotlin dari menu Baru . Masukkan DeviceInstallationService sebagai nama, lalu tekan Return.
Terapkan DeviceInstallationService menggunakan kode berikut.
package com.<your_organization>.pushdemo.services import android.annotation.SuppressLint import android.content.Context import android.provider.Settings.Secure import com.google.android.gms.common.ConnectionResult import com.google.android.gms.common.GoogleApiAvailability import io.flutter.embedding.engine.FlutterEngine import io.flutter.plugin.common.MethodCall import io.flutter.plugin.common.MethodChannel @SuppressLint("HardwareIds") class DeviceInstallationService { companion object { const val DEVICE_INSTALLATION_CHANNEL = "com.<your_organization>.pushdemo/deviceinstallation" const val GET_DEVICE_ID = "getDeviceId" const val GET_DEVICE_TOKEN = "getDeviceToken" const val GET_DEVICE_PLATFORM = "getDevicePlatform" } private var context: Context private var deviceInstallationChannel : MethodChannel val playServicesAvailable get() = GoogleApiAvailability.getInstance().isGooglePlayServicesAvailable(context) == ConnectionResult.SUCCESS constructor(context: Context, flutterEngine: FlutterEngine) { this.context = context deviceInstallationChannel = MethodChannel(flutterEngine.dartExecutor.binaryMessenger, DEVICE_INSTALLATION_CHANNEL) deviceInstallationChannel.setMethodCallHandler { call, result -> handleDeviceInstallationCall(call, result) } } fun getDeviceId() : String = Secure.getString(context.applicationContext.contentResolver, Secure.ANDROID_ID) fun getDeviceToken() : String { if(!playServicesAvailable) { throw Exception(getPlayServicesError()) } // TODO: Revisit once we have created the PushNotificationsFirebaseMessagingService val token = "Placeholder_Get_Value_From_FirebaseMessagingService_Implementation" if (token.isNullOrBlank()) { throw Exception("Unable to resolve token for FCM.") } return token } fun getDevicePlatform() : String = "fcm" private fun handleDeviceInstallationCall(call: MethodCall, result: MethodChannel.Result) { when (call.method) { GET_DEVICE_ID -> { result.success(getDeviceId()) } GET_DEVICE_TOKEN -> { getDeviceToken(result) } GET_DEVICE_PLATFORM -> { result.success(getDevicePlatform()) } else -> { result.notImplemented() } } } private fun getDeviceToken(result: MethodChannel.Result) { try { val token = getDeviceToken() result.success(token) } catch (e: Exception) { result.error("ERROR", e.message, e) } } private fun getPlayServicesError(): String { val resultCode = GoogleApiAvailability.getInstance().isGooglePlayServicesAvailable(context) if (resultCode != ConnectionResult.SUCCESS) { return if (GoogleApiAvailability.getInstance().isUserResolvableError(resultCode)){ GoogleApiAvailability.getInstance().getErrorString(resultCode) } else { "This device is not supported" } } return "An error occurred preventing the use of push notifications" } }
Catatan
Kelas ini mengimplementasikan mitra khusus platform untuk
com.<your_organization>.pushdemo/deviceinstallation
saluran. Ini didefinisikan dalam bagian Flutter dari aplikasi dalam DeviceInstallationService.dart. Dalam hal ini, panggilan dilakukan dari kode umum ke host asli. Pastikan untuk mengganti <your_organization> dengan organisasi Anda sendiri di mana pun ini digunakan.Kelas ini menyediakan ID unik (menggunakan Secure.AndroidId) sebagai bagian dari payload pendaftaran hub pemberitahuan.
Tambahkan File/Kelas Kotlin lain ke folder layanan yang disebut NotificationRegistrationService, lalu tambahkan kode berikut.
package com.<your_organization>.pushdemo.services import io.flutter.embedding.engine.FlutterEngine import io.flutter.plugin.common.MethodChannel class NotificationRegistrationService { companion object { const val NOTIFICATION_REGISTRATION_CHANNEL = "com.<your_organization>.pushdemo/notificationregistration" const val REFRESH_REGISTRATION = "refreshRegistration" } private var notificationRegistrationChannel : MethodChannel constructor(flutterEngine: FlutterEngine) { notificationRegistrationChannel = MethodChannel(flutterEngine.dartExecutor.binaryMessenger, NotificationRegistrationService.NOTIFICATION_REGISTRATION_CHANNEL) } fun refreshRegistration() { notificationRegistrationChannel.invokeMethod(REFRESH_REGISTRATION, null) } }
Catatan
Kelas ini mengimplementasikan mitra khusus platform untuk
com.<your_organization>.pushdemo/notificationregistration
saluran. Ini didefinisikan dalam bagian Flutter aplikasi dalam NotificationRegistrationService.dart. Dalam hal ini, panggilan dilakukan dari host asli ke kode umum. Sekali lagi, berhati-hatilah untuk mengganti <your_organization> dengan organisasi Anda sendiri di mana pun ini digunakan.Tambahkan File/Kelas Kotlin lain ke folder layanan yang disebut NotificationActionService, lalu tambahkan kode berikut.
package com.<your_organization>.pushdemo.services import io.flutter.embedding.engine.FlutterEngine import io.flutter.plugin.common.MethodCall import io.flutter.plugin.common.MethodChannel class NotificationActionService { companion object { const val NOTIFICATION_ACTION_CHANNEL = "com.<your_organization>.pushdemo/notificationaction" const val TRIGGER_ACTION = "triggerAction" const val GET_LAUNCH_ACTION = "getLaunchAction" } private var notificationActionChannel : MethodChannel var launchAction : String? = null constructor(flutterEngine: FlutterEngine) { notificationActionChannel = MethodChannel(flutterEngine.dartExecutor.binaryMessenger, NotificationActionService.NOTIFICATION_ACTION_CHANNEL) notificationActionChannel.setMethodCallHandler { call, result -> handleNotificationActionCall(call, result) } } fun triggerAction(action: String) { notificationActionChannel.invokeMethod(NotificationActionService.TRIGGER_ACTION, action) } private fun handleNotificationActionCall(call: MethodCall, result: MethodChannel.Result) { when (call.method) { NotificationActionService.GET_LAUNCH_ACTION -> { result.success(launchAction) } else -> { result.notImplemented() } } } }
Catatan
Kelas ini mengimplementasikan mitra khusus platform untuk
com.<your_organization>.pushdemo/notificationaction
saluran. Itu didefinisikan dalam bagian Flutter aplikasi dalam NotificationActionService.dart. Panggilan dapat dilakukan di kedua arah dalam kasus ini. Pastikan untuk mengganti <your_organization> dengan organisasi Anda sendiri di mana pun ini digunakan.Tambahkan File/Kelas Kotlin baru ke paket com.your_organization.pushdemo<> yang disebut PushNotificationsFirebaseMessagingService, lalu terapkan menggunakan kode berikut.
package com.<your_organization>.pushdemo import android.os.Handler import android.os.Looper import com.google.firebase.messaging.FirebaseMessagingService import com.google.firebase.messaging.RemoteMessage import com.<your_organization>.pushdemo.services.NotificationActionService import com.<your_organization>.pushdemo.services.NotificationRegistrationService class PushNotificationsFirebaseMessagingService : FirebaseMessagingService() { companion object { var token : String? = null var notificationRegistrationService : NotificationRegistrationService? = null var notificationActionService : NotificationActionService? = null } override fun onNewToken(token: String) { PushNotificationsFirebaseMessagingService.token = token notificationRegistrationService?.refreshRegistration() } override fun onMessageReceived(message: RemoteMessage) { message.data.let { Handler(Looper.getMainLooper()).post { notificationActionService?.triggerAction(it.getOrDefault("action", null)) } } } }
Catatan
Kelas ini bertanggung jawab untuk menangani pemberitahuan saat aplikasi berjalan di latar depan. Ini akan secara kondisional memanggil triggerAction pada NotificationActionService jika tindakan disertakan dalam payload pemberitahuan yang diterima di onMessageReceived. Ini juga akan memanggil refreshRegistration pada NotificationRegistrationService ketika token Firebase diregenerasi dengan menimpa fungsi onNewToken .
Sekali lagi, berhati-hatilah untuk mengganti <your_organization> dengan organisasi Anda sendiri di mana pun digunakan.
Di AndroidManifest.xml (app>src>main), tambahkan PushNotificationsFirebaseMessagingService ke bagian bawah elemen aplikasi dengan
com.google.firebase.MESSAGING_EVENT
filter niat.<manifest> <application> <!-- EXISTING MANIFEST CONTENT --> <service android:name="com.<your_organization>.pushdemo.PushNotificationsFirebaseMessagingService" android:exported="false"> <intent-filter> <action android:name="com.google.firebase.MESSAGING_EVENT" /> </intent-filter> </service> </application> </manifest>
Kembali ke DeviceInstallationService, pastikan impor berikut ada di bagian atas file.
package com.<your_organization>.pushdemo import com.<your_organization>.pushdemo.services.PushNotificationsFirebaseMessagingService
Catatan
Ganti <your_organization> dengan nilai organisasi Anda sendiri.
Perbarui teks tempat penampung Placeholder_Get_Value_From_FirebaseMessagingService_Implementation untuk mendapatkan nilai token dari PushNotificationFirebaseMessagingService.
fun getDeviceToken() : String { if(!playServicesAvailable) { throw Exception(getPlayServicesError()) } // Get token from the PushNotificationsFirebaseMessagingService.token field. val token = PushNotificationsFirebaseMessagingService.token if (token.isNullOrBlank()) { throw Exception("Unable to resolve token for FCM.") } return token }
Di MainActivity, pastikan impor berikut ada di bagian atas file.
package com.<your_organization>.pushdemo import android.content.Intent import android.os.Bundle import com.google.android.gms.tasks.OnCompleteListener import com.google.firebase.iid.FirebaseInstanceId import com.<your_organization>.pushdemo.services.DeviceInstallationService import com.<your_organization>.pushdemo.services.NotificationActionService import com.<your_organization>.pushdemo.services.NotificationRegistrationService import io.flutter.embedding.android.FlutterActivity
Catatan
Ganti <your_organization> dengan nilai organisasi Anda sendiri.
Tambahkan variabel untuk menyimpan referensi ke DeviceInstallationService.
private lateinit var deviceInstallationService: DeviceInstallationService
Tambahkan fungsi yang disebut processNotificationActions untuk memeriksa apakah Niat memiliki nilai tambahan bernama tindakan. Secara kondisional memicu tindakan tersebut atau menyimpannya untuk digunakan nanti jika tindakan sedang diproses selama peluncuran aplikasi.
private fun processNotificationActions(intent: Intent, launchAction: Boolean = false) { if (intent.hasExtra("action")) { var action = intent.getStringExtra("action"); if (action.isNotEmpty()) { if (launchAction) { PushNotificationsFirebaseMessagingService.notificationActionService?.launchAction = action } else { PushNotificationsFirebaseMessagingService.notificationActionService?.triggerAction(action) } } } }
Ambil alih fungsi onNewIntent untuk memanggil processNotificationActions.
override fun onNewIntent(intent: Intent) { super.onNewIntent(intent) processNotificationActions(intent) }
Catatan
Karena LaunchMode untuk MainActivity diatur ke SingleTop, Niat akan dikirim ke instans Aktivitas yang ada melalui fungsi onNewIntent daripada fungsi onCreate sehingga Anda harus menangani Niat masuk dalam fungsi onCreate dan onNewIntent .
Ambil alih fungsi onCreate , atur deviceInstallationService ke instans baru DeviceInstallationService.
override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) flutterEngine?.let { deviceInstallationService = DeviceInstallationService(context, it) } }
Atur properti notificationActionService dan notificationRegistrationService di PushNotificationFirebaseMessagingServices.
flutterEngine?.let { deviceInstallationService = DeviceInstallationService(context, it) PushNotificationsFirebaseMessagingService.notificationActionService = NotificationActionService(it) PushNotificationsFirebaseMessagingService.notificationRegistrationService = NotificationRegistrationService(it) }
Dalam fungsi yang sama, panggil FirebaseInstanceId.getInstance().instanceId secara kondisional. Terapkan OnCompleteListener untuk mengatur nilai token yang dihasilkan pada PushNotificationFirebaseMessagingService sebelum memanggil refreshRegistration.
if(deviceInstallationService?.playServicesAvailable) { FirebaseInstanceId.getInstance().instanceId .addOnCompleteListener(OnCompleteListener { task -> if (!task.isSuccessful) return@OnCompleteListener PushNotificationsFirebaseMessagingService.token = task.result?.token PushNotificationsFirebaseMessagingService.notificationRegistrationService?.refreshRegistration() }) }
Masih dalam onCreate, panggil processNotificationActions di akhir fungsi. Gunakan true untuk argumen launchAction untuk menunjukkan tindakan ini sedang diproses selama peluncuran aplikasi.
processNotificationActions(this.intent, true)
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 target runner dan Info.plist
Di Visual Studio Code, Kontrol + Klik folder ios, lalu pilih Buka di Xcode.
Di Xcode, klik Runner ( xcodeproj di bagian atas, bukan folder) lalu pilih target Runner , lalu Signing & Capabilities. Dengan konfigurasi Semua build dipilih, pilih akun Pengembang Anda untuk Tim. Pastikan opsi "Kelola penandatanganan secara otomatis" dicentang dan Sertifikat Penandatanganan dan Profil Provisi Anda dipilih secara otomatis.
Catatan
Jika Anda tidak melihat nilai Profil Provisi baru, coba refresh profil untuk Identitas Penandatanganan dengan memilihAkunPreferensi>Xcode>, lalu pilih tombol Unduh Profil Manual untuk mengunduh profil.
Klik + Kemampuan, lalu cari Pemberitahuan Push. Klik Dua Kalipada Pemberitahuan Push untuk menambahkan kemampuan ini.
Buka Info.plist dan 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.
Buka Runner.entitlements dan pastikan pengaturan Lingkungan APS diatur ke pengembangan.
Menangani pemberitahuan push untuk iOS
Kontrol + Klik folder Runner (dalam proyek Runner), lalu pilih Grup Baru menggunakan Layanan sebagai nama.
Kontrol + Klik folder Layanan , lalu pilih File Baru.... Lalu, pilih File Swift dan klik Berikutnya. Tentukan DeviceInstallationService untuk nama tersebut lalu klik Buat.
Terapkan DeviceInstallationService.swift menggunakan kode berikut.
import Foundation class DeviceInstallationService { enum DeviceRegistrationError: Error { case notificationSupport(message: String) } var token : Data? = nil let DEVICE_INSTALLATION_CHANNEL = "com.<your_organization>.pushdemo/deviceinstallation" let GET_DEVICE_ID = "getDeviceId" let GET_DEVICE_TOKEN = "getDeviceToken" let GET_DEVICE_PLATFORM = "getDevicePlatform" private let deviceInstallationChannel : FlutterMethodChannel var notificationsSupported : Bool { get { if #available(iOS 13.0, *) { return true } else { return false } } } init(withBinaryMessenger binaryMessenger : FlutterBinaryMessenger) { deviceInstallationChannel = FlutterMethodChannel(name: DEVICE_INSTALLATION_CHANNEL, binaryMessenger: binaryMessenger) deviceInstallationChannel.setMethodCallHandler(handleDeviceInstallationCall) } func getDeviceId() -> String { return UIDevice.current.identifierForVendor!.description } func getDeviceToken() throws -> String { if(!notificationsSupported) { let notificationSupportError = getNotificationsSupportError() throw DeviceRegistrationError.notificationSupport(message: notificationSupportError) } if (token == nil) { throw DeviceRegistrationError.notificationSupport(message: "Unable to resolve token for APNS.") } return token!.reduce("", {$0 + String(format: "%02X", $1)}) } func getDevicePlatform() -> String { return "apns" } private func handleDeviceInstallationCall(call: FlutterMethodCall, result: @escaping FlutterResult) { switch call.method { case GET_DEVICE_ID: result(getDeviceId()) case GET_DEVICE_TOKEN: getDeviceToken(result: result) case GET_DEVICE_PLATFORM: result(getDevicePlatform()) default: result(FlutterMethodNotImplemented) } } private func getDeviceToken(result: @escaping FlutterResult) { do { let token = try getDeviceToken() result(token) } catch let error { result(FlutterError(code: "UNAVAILABLE", message: error.localizedDescription, details: nil)) } } private func getNotificationsSupportError() -> String { if (!notificationsSupported) { return "This app only supports notifications on iOS 13.0 and above. You are running \(UIDevice.current.systemVersion)" } return "An error occurred preventing the use of push notifications." } }
Catatan
Kelas ini mengimplementasikan mitra khusus platform untuk
com.<your_organization>.pushdemo/deviceinstallation
saluran. Ini didefinisikan dalam bagian Flutter dari aplikasi dalam DeviceInstallationService.dart. Dalam hal ini, panggilan dilakukan dari kode umum ke host asli. Pastikan untuk mengganti <your_organization> dengan organisasi Anda sendiri di mana pun ini digunakan.Kelas ini menyediakan ID unik (menggunakan nilai UIDevice.identifierForVendor ) sebagai bagian dari payload pendaftaran hub pemberitahuan.
Tambahkan File Swift lain ke folder Layanan yang disebut NotificationRegistrationService, lalu tambahkan kode berikut.
import Foundation class NotificationRegistrationService { let NOTIFICATION_REGISTRATION_CHANNEL = "com.<your_organization>.pushdemo/notificationregistration" let REFRESH_REGISTRATION = "refreshRegistration" private let notificationRegistrationChannel : FlutterMethodChannel init(withBinaryMessenger binaryMessenger : FlutterBinaryMessenger) { notificationRegistrationChannel = FlutterMethodChannel(name: NOTIFICATION_REGISTRATION_CHANNEL, binaryMessenger: binaryMessenger) } func refreshRegistration() { notificationRegistrationChannel.invokeMethod(REFRESH_REGISTRATION, arguments: nil) } }
Catatan
Kelas ini mengimplementasikan mitra khusus platform untuk
com.<your_organization>.pushdemo/notificationregistration
saluran. Ini didefinisikan dalam bagian Flutter aplikasi dalam NotificationRegistrationService.dart. Dalam hal ini, panggilan dilakukan dari host asli ke kode umum. Sekali lagi, berhati-hatilah untuk mengganti <your_organization> dengan organisasi Anda sendiri di mana pun ini digunakan.Tambahkan File Swift lain ke folder Layanan yang disebut NotificationActionService, lalu tambahkan kode berikut.
import Foundation class NotificationActionService { let NOTIFICATION_ACTION_CHANNEL = "com.<your_organization>.pushdemo/notificationaction" let TRIGGER_ACTION = "triggerAction" let GET_LAUNCH_ACTION = "getLaunchAction" private let notificationActionChannel: FlutterMethodChannel var launchAction: String? = nil init(withBinaryMessenger binaryMessenger: FlutterBinaryMessenger) { notificationActionChannel = FlutterMethodChannel(name: NOTIFICATION_ACTION_CHANNEL, binaryMessenger: binaryMessenger) notificationActionChannel.setMethodCallHandler(handleNotificationActionCall) } func triggerAction(action: String) { notificationActionChannel.invokeMethod(TRIGGER_ACTION, arguments: action) } private func handleNotificationActionCall(call: FlutterMethodCall, result: @escaping FlutterResult) { switch call.method { case GET_LAUNCH_ACTION: result(launchAction) default: result(FlutterMethodNotImplemented) } } }
Catatan
Kelas ini mengimplementasikan mitra khusus platform untuk
com.<your_organization>.pushdemo/notificationaction
saluran. Itu didefinisikan dalam bagian Flutter aplikasi dalam NotificationActionService.dart. Panggilan dapat dilakukan di kedua arah dalam kasus ini. Pastikan untuk mengganti <your_organization> dengan organisasi Anda sendiri di mana pun ini digunakan.Di AppDelegate.swift, tambahkan variabel untuk menyimpan referensi ke layanan yang Anda buat sebelumnya.
var deviceInstallationService : DeviceInstallationService? var notificationRegistrationService : NotificationRegistrationService? var notificationActionService : NotificationActionService?
Tambahkan fungsi yang disebut processNotificationActions untuk memproses data pemberitahuan. Secara kondisional memicu tindakan tersebut atau menyimpannya untuk digunakan nanti jika tindakan sedang diproses selama peluncuran aplikasi.
func processNotificationActions(userInfo: [AnyHashable : Any], launchAction: Bool = false) { if let action = userInfo["action"] as? String { if (launchAction) { notificationActionService?.launchAction = action } else { notificationActionService?.triggerAction(action: action) } } }
Ambil alih fungsi didRegisterForRemoteNotificationsWithDeviceToken yang mengatur nilai token untuk DeviceInstallationService. Kemudian, panggil refreshRegistration pada NotificationRegistrationService.
override func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) { deviceInstallationService?.token = deviceToken notificationRegistrationService?.refreshRegistration() }
Ambil alih fungsi didReceiveRemoteNotification yang meneruskan argumen userInfo ke fungsi processNotificationActions .
override func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable : Any]) { processNotificationActions(userInfo: userInfo) }
Ambil alih fungsi didFailToRegisterForRemoteNotificationsWithError untuk mencatat kesalahan.
override func application(_ application: UIApplication, didFailToRegisterForRemoteNotificationsWithError error: Error) { print(error); }
Catatan
Ini tempat penampung yang sangat banyak. Anda akan ingin menerapkan pencatatan dan penanganan kesalahan yang tepat untuk skenario produksi.
Dalam didFinishLaunchingWithOptions, buat instans variabel deviceInstallationService, notificationRegistrationService, dan notificationActionService .
let controller : FlutterViewController = window?.rootViewController as! FlutterViewController deviceInstallationService = DeviceInstallationService(withBinaryMessenger: controller.binaryMessenger) notificationRegistrationService = NotificationRegistrationService(withBinaryMessenger: controller.binaryMessenger) notificationActionService = NotificationActionService(withBinaryMessenger: controller.binaryMessenger)
Dalam fungsi yang sama, minta otorisasi secara kondisional dan daftar untuk pemberitahuan jarak jauh.
if #available(iOS 13.0, *) { UNUserNotificationCenter.current().requestAuthorization(options: [.alert, .sound, .badge]) { (granted, error) in if (granted) { DispatchQueue.main.async { let pushSettings = UIUserNotificationSettings(types: [.alert, .sound, .badge], categories: nil) application.registerUserNotificationSettings(pushSettings) application.registerForRemoteNotifications() } } } }
Jika launchOptions berisi kunci remoteNotification , panggil processNotificationActions di akhir fungsi didFinishLaunchingWithOptions . Berikan objek userInfo yang dihasilkan dan gunakan true untuk argumen launchAction . Nilai benar menunjukkan bahwa tindakan sedang diproses selama peluncuran aplikasi.
if let userInfo = launchOptions?[.remoteNotification] as? [AnyHashable : Any] { processNotificationActions(userInfo: userInfo, launchAction: true) }
Menguji solusi
Anda sekarang dapat menguji pengiriman pemberitahuan melalui layanan backend.
Mengirim pemberitahuan pengujian
Buka tab baru di Postman.
Atur permintaan ke POST, dan masukkan alamat berikut:
https://<app_name>.azurewebsites.net/api/notifications/requests
Jika Anda memilih untuk menyelesaikan bagian Autentikasi klien menggunakan Kunci API , pastikan untuk mengonfigurasi header permintaan untuk menyertakan nilai apikey Anda.
Kunci Nilai apikey <your_api_key> 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" }
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" }
Jalankan aplikasi PushDemo pada salah 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.
Di aplikasi PushDemo , ketuk tombol Daftar .
Kembali ke Postman, tutup jendela Hasilkan Cuplikan Kode (jika Anda belum melakukannya) lalu klik tombol Kirim .
Validasi bahwa Anda mendapatkan respons 200 OK di Postman dan pemberitahuan muncul di aplikasi yang menampilkan tindakan ActionA yang diterima.
Tutup aplikasi PushDemo , lalu klik tombol Kirim lagi di Postman.
Validasi bahwa Anda mendapatkan respons 200 OK di Postman lagi. Validasi bahwa pemberitahuan muncul di area pemberitahuan untuk aplikasi PushDemo dengan pesan yang benar.
Ketuk pemberitahuan untuk mengonfirmasi bahwa pemberitahuan membuka aplikasi dan menampilkan pemberitahuan tindakan ActionA yang diterima .
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 }
Dengan aplikasi masih terbuka, klik tombol Kirim di Postman.
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.
Tutup aplikasi PushDemo , lalu klik tombol Kirim lagi di Postman.
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 apakah 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 menjadi https://<api_name>.azurewebsites.net/
atau https://localhost:5001/
saat pengujian 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 bagian Autentikasi klien menggunakan 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.
Tautan terkait
- Gambaran umum Azure Notification Hubs
- Menginstal Flutter di macOS
- Menginstal Flutter di Windows
- Notification Hubs SDK untuk operasi back-end
- Notification Hubs SDK di GitHub
- Mendaftar dengan backend aplikasi
- Manajemen pendaftaran
- Bekerja dengan tag
- Bekerja dengan templat kustom
Langkah berikutnya
Anda sekarang harus memiliki aplikasi Flutter 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.