向 Xamarin.Android 应用添加推送通知
概述
本教程介绍如何向 Xamarin.Android 快速入门项目添加推送通知,以便每次插入一条记录时,都向设备发送一条推送通知。
如果不使用下载的快速入门服务器项目,则需要推送通知扩展包。 有关详细信息,请参阅使用适用于 Azure 移动应用的 .NET 后端服务器 SDK 指南。
先决条件
本教程需要设置:
- 有效的 Google 帐户 可以在 accounts.google.com 注册 Google 帐户。
- Google Cloud Messaging 客户端组件。
配置通知中心
Azure 应用服务的移动应用功能使用 Azure 通知中心发送推送内容,因此用户需为移动应用配置通知中心。
在 Azure 门户中,转到“应用服务”,并选择应用后端。 在“设置”下,选择“推送”。
若要将通知中心资源添加到应用中,请选择“连接”。 可以创建一个中心,也可以连接到一个现有的中心。
现在已将通知中心连接到移动应用后端项目。 稍后需对此通知中心进行配置,以便连接到将内容推送到设备的平台通知系统 (PNS)。
启用 Firebase Cloud Messaging
登录到 Firebase 控制台。 如果还没有 Firebase 项目,创建一个新项目。
创建项目后,选择“向 Android 应用添加 Firebase”。
在“将 Firebase 添加到 Android 应用”页上,执行以下步骤:
对于“Android 程序包名称”,请在应用程序的 build.gradle 文件中复制 applicationId 的值。 在此示例中,它是
com.fabrikam.fcmtutorial1app
。选择“注册应用”。
选择“下载 google-services.json”,将该文件保存到项目的 app 文件夹中,然后选择“下一步”。
在 Android Studio 中对你的项目进行以下配置更改。
在项目级 build.gradle 文件 (<project>/build.gradle) 中,向 dependencies 部分中添加以下语句。
classpath 'com.google.gms:google-services:4.0.1'
在应用级 build.gradle 文件 (<project>/<app-module>/build.gradle) 中,向 dependencies 部分中添加以下语句。
implementation 'com.google.firebase:firebase-core:16.0.8' implementation 'com.google.firebase:firebase-messaging:17.3.4'
在应用级 build.gradle 文件的末尾,在 dependencies 部分后面添加以下行。
apply plugin: 'com.google.gms.google-services'
在工具栏上选择“立即同步”。
选择“下一步” 。
选择“跳过此步骤”。
在 Firebase 控制台中,选择与项目相对应的齿轮图标。 然后,选择“项目设置”。
如果尚未将 google-services.json 文件下载到你的 Android Studio 项目的 app 文件夹中,则可以在此页面上执行此操作。
切换到顶部的“Cloud Messaging”选项卡。
复制并保存服务器密钥以供将来使用。 此值将用于配置中心。
配置 Azure 以发送推送请求
在Azure 门户中,单击“浏览全部”>“应用服务”,并单击移动应用后端。 在“设置”下,单击“应用服务推送”,并单击通知中心名称。
转到“Google (GCM)”,输入上一步骤中从 Firebase 获取的“服务器密钥”值,并单击“保存”。
移动应用后端现在已配置为使用 Firebase Cloud Messaging。 这样便可通过使用通知中心将推送通知发送到 Android 设备上运行的应用。
更新服务器项目以发送推送通知
在本部分中,更新现有移动应用后端项目中的代码,以便在每次添加新项目时发送推送通知。 此过程由 Azure 通知中心的模板功能提供支持,允许跨平台推送。 各种客户端使用模板注册推送通知,因此只需单个通用推送即可将内容发送到所有客户端平台。
选择其中一个与后端项目类型(.NET 后端或 Node.js 后端)匹配的过程。
.NET 后端项目
在 Visual Studio 中,右键单击服务器项目。 然后选择“管理 NuGet 包”。 搜索
Microsoft.Azure.NotificationHubs
,并选择“安装” 。 此过程将安装通知中心库,以便从后端发送通知。在服务器项目中,打开“控制器”>“TodoItemController.cs”。 然后,添加以下 using 语句:
using System.Collections.Generic; using Microsoft.Azure.NotificationHubs; using Microsoft.Azure.Mobile.Server.Config;
在 PostTodoItem 方法中,在调用 InsertAsync 后添加如下代码:
// Get the settings for the server project. HttpConfiguration config = this.Configuration; MobileAppSettingsDictionary settings = this.Configuration.GetMobileAppSettingsProvider().GetMobileAppSettings(); // Get the Notification Hubs credentials for the mobile app. string notificationHubName = settings.NotificationHubName; string notificationHubConnection = settings .Connections[MobileAppSettingsKeys.NotificationHubConnectionString].ConnectionString; // Create a new Notification Hub client. NotificationHubClient hub = NotificationHubClient .CreateClientFromConnectionString(notificationHubConnection, notificationHubName); // Send the message so that all template registrations that contain "messageParam" // receive the notifications. This includes APNS, GCM, WNS, and MPNS template registrations. Dictionary<string,string> templateParams = new Dictionary<string,string>(); templateParams["messageParam"] = item.Text + " was added to the list."; try { // Send the push notification and log the results. var result = await hub.SendTemplateNotificationAsync(templateParams); // Write the success result to the logs. config.Services.GetTraceWriter().Info(result.State.ToString()); } catch (System.Exception ex) { // Write the failure result to the logs. config.Services.GetTraceWriter() .Error(ex.Message, null, "Push.SendAsync Error"); }
插入新项时,此过程将发送一个包含 item.Text 的模板通知。
重新发布服务器项目。
Node.js 后端项目
设置后端项目。
将 todoitem.js 文件中的现有代码替换为以下代码:
var azureMobileApps = require('azure-mobile-apps'), promises = require('azure-mobile-apps/src/utilities/promises'), logger = require('azure-mobile-apps/src/logger'); var table = azureMobileApps.table(); table.insert(function (context) { // For more information about the Notification Hubs JavaScript SDK, // see https://aka.ms/nodejshubs. logger.info('Running TodoItem.insert'); // Define the template payload. var payload = '{"messageParam": "' + context.item.text + '" }'; // Execute the insert. The insert returns the results as a promise. // Do the push as a post-execute action within the promise flow. return context.execute() .then(function (results) { // Only do the push if configured. if (context.push) { // Send a template notification. context.push.send(null, payload, function (error) { if (error) { logger.error('Error while sending push notification: ', error); } else { logger.info('Push notification sent successfully!'); } }); } // Don't forget to return the results from the context.execute(). return results; }) .catch(function (error) { logger.error('Error while running context.execute: ', error); }); }); module.exports = table;
插入新项时,此过程将发送一个包含 item.text 的模板通知。
编辑本地计算机上的文件时,请重新发布服务器项目。
针对推送通知配置客户端项目
在 Visual Studio) 的解决方案视图中,右键单击“组件”文件夹,单击“获取更多组件...”,搜索 Google Cloud Messaging 客户端组件并将其添加到项目中 (或解决方案资源管理器。
打开 ToDoActivity.cs 项目文件,将以下 using 语句添加到类:
using Gcm.Client;
在 ToDoActivity 类中,添加以下新代码:
// Create a new instance field for this activity. static ToDoActivity instance = new ToDoActivity(); // Return the current activity instance. public static ToDoActivity CurrentActivity { get { return instance; } } // Return the Mobile Services client. public MobileServiceClient CurrentClient { get { return client; } }
这样便可以通过推送处理程序服务流程访问移动客户端实例。
创建 MobileServiceClient 后,将以下代码添加到 OnCreate 方法:
// Set the current instance of TodoActivity. instance = this; // Make sure the GCM client is set up correctly. GcmClient.CheckDevice(this); GcmClient.CheckManifest(this); // Register the app for push notifications. GcmClient.Register(this, ToDoBroadcastReceiver.senderIDs);
ToDoActivity 现已准备就绪,可以添加推送通知了。
向应用程序添加推送通知代码
在名为
ToDoBroadcastReceiver
的项目中创建一个新类。将以下 using 语句添加到 ToDoBroadcastReceiver 类:
using Gcm.Client; using Microsoft.WindowsAzure.MobileServices; using Newtonsoft.Json.Linq;
在 using 语句和 namespace 声明之间添加以下权限请求:
[assembly: Permission(Name = "@PACKAGE_NAME@.permission.C2D_MESSAGE")] [assembly: UsesPermission(Name = "@PACKAGE_NAME@.permission.C2D_MESSAGE")] [assembly: UsesPermission(Name = "com.google.android.c2dm.permission.RECEIVE")] //GET_ACCOUNTS is only needed for android versions 4.0.3 and below [assembly: UsesPermission(Name = "android.permission.GET_ACCOUNTS")] [assembly: UsesPermission(Name = "android.permission.INTERNET")] [assembly: UsesPermission(Name = "android.permission.WAKE_LOCK")]
将现有的 ToDoBroadcastReceiver 类定义替换为以下代码:
[BroadcastReceiver(Permission = Gcm.Client.Constants.PERMISSION_GCM_INTENTS)] [IntentFilter(new string[] { Gcm.Client.Constants.INTENT_FROM_GCM_MESSAGE }, Categories = new string[] { "@PACKAGE_NAME@" })] [IntentFilter(new string[] { Gcm.Client.Constants.INTENT_FROM_GCM_REGISTRATION_CALLBACK }, Categories = new string[] { "@PACKAGE_NAME@" })] [IntentFilter(new string[] { Gcm.Client.Constants.INTENT_FROM_GCM_LIBRARY_RETRY }, Categories = new string[] { "@PACKAGE_NAME@" })] public class ToDoBroadcastReceiver : GcmBroadcastReceiverBase<PushHandlerService> { // Set the Google app ID. public static string[] senderIDs = new string[] { "<PROJECT_NUMBER>" }; }
在上述代码中,必须将
<PROJECT_NUMBER>
替换为在 Google 开发人员门户中设置应用程序时 Google 分配的项目编号。在 ToDoBroadcastReceiver.cs 项目文件中,添加定义 PushHandlerService 类的以下代码:
// The ServiceAttribute must be applied to the class. [Service] public class PushHandlerService : GcmServiceBase { public static string RegistrationID { get; private set; } public PushHandlerService() : base(ToDoBroadcastReceiver.senderIDs) { } }
请注意,此类派生自 GcmServiceBase,“服务”属性必须应用于此类。
注意
GcmServiceBase 类实现 OnRegistered()、OnUnRegistered()、OnMessage() 和 OnError() 方法。 必须在 PushHandlerService 类中重写这些方法。
将以下代码添加到 PushHandlerService 类,以便重写 OnRegistered 事件处理程序。
protected override void OnRegistered(Context context, string registrationId) { System.Diagnostics.Debug.WriteLine("The device has been registered with GCM.", "Success!"); // Get the MobileServiceClient from the current activity instance. MobileServiceClient client = ToDoActivity.CurrentActivity.CurrentClient; var push = client.GetPush(); // Define a message body for GCM. const string templateBodyGCM = "{\"data\":{\"message\":\"$(messageParam)\"}}"; // Define the template registration as JSON. JObject templates = new JObject(); templates["genericMessage"] = new JObject { {"body", templateBodyGCM } }; try { // Make sure we run the registration on the same thread as the activity, // to avoid threading errors. ToDoActivity.CurrentActivity.RunOnUiThread( // Register the template with Notification Hubs. async () => await push.RegisterAsync(registrationId, templates)); System.Diagnostics.Debug.WriteLine( string.Format("Push Installation Id", push.InstallationId.ToString())); } catch (Exception ex) { System.Diagnostics.Debug.WriteLine( string.Format("Error with Azure push registration: {0}", ex.Message)); } }
此方法使用返回的 GCM 注册 ID 向 Azure 注册以获取推送通知。 仅能在创建注册后向其添加标记。 有关详细信息,请参阅如何:将标记添加到设备安装以启用“推送到标记”。
在 PushHandlerService 中使用以下代码重写 OnMessage 方法:
protected override void OnMessage(Context context, Intent intent) { string message = string.Empty; // Extract the push notification message from the intent. if (intent.Extras.ContainsKey("message")) { message = intent.Extras.Get("message").ToString(); var title = "New item added:"; // Create a notification manager to send the notification. var notificationManager = GetSystemService(Context.NotificationService) as NotificationManager; // Create a new intent to show the notification in the UI. PendingIntent contentIntent = PendingIntent.GetActivity(context, 0, new Intent(this, typeof(ToDoActivity)), 0); // Create the notification using the builder. var builder = new Notification.Builder(context); builder.SetAutoCancel(true); builder.SetContentTitle(title); builder.SetContentText(message); builder.SetSmallIcon(Resource.Drawable.ic_launcher); builder.SetContentIntent(contentIntent); var notification = builder.Build(); // Display the notification in the Notifications Area. notificationManager.Notify(1, notification); } }
使用以下代码重写 OnUnRegistered() 和 OnError() 方法。
protected override void OnUnRegistered(Context context, string registrationId) { throw new NotImplementedException(); } protected override void OnError(Context context, string errorId) { System.Diagnostics.Debug.WriteLine( string.Format("Error occurred in the notification: {0}.", errorId)); }
在应用程序中测试推送通知
可以使用模拟器中的虚拟设备测试应用。 在模拟器中运行时,还需要其他配置步骤。
虚拟设备必须将 Google API 设置为 Android 虚拟设备 (AVD) 管理器中的目标。
单击 “应用>设置>添加”帐户,将 Google 帐户添加到 Android 设备,然后按照提示进行操作。
像以前一样运行 todolist 应用并插入一个新的 todo 项。 此时通知区域中会显示一个通知图标。 可以打开通知抽屉查看通知的完整文本。