向 Xamarin.Android 应用添加推送通知

概述

本教程介绍如何向 Xamarin.Android 快速入门项目添加推送通知,以便每次插入一条记录时,都向设备发送一条推送通知。

如果不使用下载的快速入门服务器项目,则需要推送通知扩展包。 有关详细信息,请参阅使用适用于 Azure 移动应用的 .NET 后端服务器 SDK 指南。

先决条件

本教程需要设置:

配置通知中心

Azure 应用服务的移动应用功能使用 Azure 通知中心发送推送内容,因此用户需为移动应用配置通知中心。

  1. Azure 门户中,转到“应用服务”,并选择应用后端。 在“设置”下,选择“推送”

  2. 若要将通知中心资源添加到应用中,请选择“连接”。 可以创建一个中心,也可以连接到一个现有的中心。

    配置中心

现在已将通知中心连接到移动应用后端项目。 稍后需对此通知中心进行配置,以便连接到将内容推送到设备的平台通知系统 (PNS)。

启用 Firebase Cloud Messaging

  1. 登录到 Firebase 控制台。 如果还没有 Firebase 项目,创建一个新项目。

  2. 创建项目后,选择“向 Android 应用添加 Firebase”。

    将 Firebase 添加到 Android 应用

  3. 在“将 Firebase 添加到 Android 应用”页上,执行以下步骤:

    1. 对于“Android 程序包名称”,请在应用程序的 build.gradle 文件中复制 applicationId 的值。 在此示例中,它是 com.fabrikam.fcmtutorial1app

      指定程序包名称

    2. 选择“注册应用”。

  4. 选择“下载 google-services.json”,将该文件保存到项目的 app 文件夹中,然后选择“下一步”

    下载 google-services.json

  5. 在 Android Studio 中对你的项目进行以下配置更改

    1. 在项目级 build.gradle 文件 (<project>/build.gradle) 中,向 dependencies 部分中添加以下语句。

      classpath 'com.google.gms:google-services:4.0.1'
      
    2. 在应用级 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'
      
    3. 在应用级 build.gradle 文件的末尾,在 dependencies 部分后面添加以下行。

      apply plugin: 'com.google.gms.google-services'
      
    4. 在工具栏上选择“立即同步”。

      build.gradle 配置更改

  6. 选择“下一步” 。

  7. 选择“跳过此步骤”

    跳过最后一步

  8. 在 Firebase 控制台中,选择与项目相对应的齿轮图标。 然后,选择“项目设置”。

    选择“项目设置”

  9. 如果尚未将 google-services.json 文件下载到你的 Android Studio 项目的 app 文件夹中,则可以在此页面上执行此操作。

  10. 切换到顶部的“Cloud Messaging”选项卡。

  11. 复制并保存服务器密钥以供将来使用。 此值将用于配置中心。

配置 Azure 以发送推送请求

  1. Azure 门户中,单击“浏览全部”>“应用服务”,并单击移动应用后端。 在“设置”下,单击“应用服务推送”,并单击通知中心名称。

  2. 转到“Google (GCM)”,输入上一步骤中从 Firebase 获取的“服务器密钥”值,并单击“保存”

    在门户中设置 API 密钥

移动应用后端现在已配置为使用 Firebase Cloud Messaging。 这样便可通过使用通知中心将推送通知发送到 Android 设备上运行的应用。

更新服务器项目以发送推送通知

在本部分中,更新现有移动应用后端项目中的代码,以便在每次添加新项目时发送推送通知。 此过程由 Azure 通知中心的模板功能提供支持,允许跨平台推送。 各种客户端使用模板注册推送通知,因此只需单个通用推送即可将内容发送到所有客户端平台。

选择其中一个与后端项目类型(.NET 后端Node.js 后端)匹配的过程。

.NET 后端项目

  1. 在 Visual Studio 中,右键单击服务器项目。 然后选择“管理 NuGet 包”。 搜索 Microsoft.Azure.NotificationHubs,并选择“安装” 。 此过程将安装通知中心库,以便从后端发送通知。

  2. 在服务器项目中,打开“控制器”>“TodoItemController.cs”。 然后,添加以下 using 语句:

    using System.Collections.Generic;
    using Microsoft.Azure.NotificationHubs;
    using Microsoft.Azure.Mobile.Server.Config;
    
  3. 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 的模板通知。

  4. 重新发布服务器项目。

Node.js 后端项目

  1. 设置后端项目。

  2. 将 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 的模板通知。

  3. 编辑本地计算机上的文件时,请重新发布服务器项目。

针对推送通知配置客户端项目

  1. 在 Visual Studio) 的解决方案视图中,右键单击“组件”文件夹,单击“获取更多组件...”,搜索 Google Cloud Messaging 客户端组件并将其添加到项目中 (或解决方案资源管理器

  2. 打开 ToDoActivity.cs 项目文件,将以下 using 语句添加到类:

    using Gcm.Client;
    
  3. 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;
        }
    }
    

    这样便可以通过推送处理程序服务流程访问移动客户端实例。

  4. 创建 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 现已准备就绪,可以添加推送通知了。

向应用程序添加推送通知代码

  1. 在名为 ToDoBroadcastReceiver 的项目中创建一个新类。

  2. 将以下 using 语句添加到 ToDoBroadcastReceiver 类:

    using Gcm.Client;
    using Microsoft.WindowsAzure.MobileServices;
    using Newtonsoft.Json.Linq;
    
  3. 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")]
    
  4. 将现有的 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 分配的项目编号。

  5. 在 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 类中重写这些方法。

  6. 将以下代码添加到 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 注册以获取推送通知。 仅能在创建注册后向其添加标记。 有关详细信息,请参阅如何:将标记添加到设备安装以启用“推送到标记”

  7. 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);
    
        }
    }
    
  8. 使用以下代码重写 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));
    }
    

在应用程序中测试推送通知

可以使用模拟器中的虚拟设备测试应用。 在模拟器中运行时,还需要其他配置步骤。

  1. 虚拟设备必须将 Google API 设置为 Android 虚拟设备 (AVD) 管理器中的目标。

  2. 单击 “应用>设置>添加”帐户,将 Google 帐户添加到 Android 设备,然后按照提示进行操作。

  3. 像以前一样运行 todolist 应用并插入一个新的 todo 项。 此时通知区域中会显示一个通知图标。 可以打开通知抽屉查看通知的完整文本。