Azure 通知中心:如何从 .net 后端向单个用户发送本地化的、平台无关的推送通知?

Azure Notification Hubs: How to send localized, platform independent push notifications to individual users from a .net backend?

场景

我正在为本地化的跨平台移动应用程序开发后端,并希望在后端发生某些事件时向用户发送推送通知。

这些应用程序是为 iOSandroid 使用 xamarin,后端是一个 web-api 2,它使用 Azure 通知中心.

目前的工作

目前,移动应用程序使用 Installations 通过 Web-API 注册通知。通过 web-API 注册是必要的,因为服务器会创建一个唯一的用户标签,用于在发送消息时识别用户。我目前能够从 Azure 后端的“调试”部分向注册的 iOS 设备发送测试通知。这是处理注册的代码:

[HttpPut]
[Route("")]
public async Task<IHttpActionResult> CreateOrUpdateDeviceInstallation(DeviceInstallationModel deviceInstallationModel)
{
    var installation = new Installation
    {
        InstallationId = deviceInstallationModel.InstallationId,
        PushChannel = deviceInstallationModel.Handle
    };

    switch (deviceInstallationModel.Platform)
    {
        case "apns":
            installation.Platform = NotificationPlatform.Apns;
            break;
        case "gcm":
            installation.Platform = NotificationPlatform.Gcm;
            break;
        default:

            return BadRequest("The given platform is not supported");
    }

    installation.Tags = new List<string>{ OwnerId }; 
    //OwnerId is the server generated unique user tag

    await _notificationHubClient.CreateOrUpdateInstallationAsync(installation);

    return Ok();
}


public class DeviceInstallationModel
{
    public string InstallationId { get; set; }
    public string Platform { get; set; }
    public string Handle { get; set; }
}

我的问题

我现在需要在后端发生某些事件时发送 localized 推送通知。我正在尝试实现这一点 ,而后端对应用程序的区域设置或应用程序的平台一无所知。据我从文档 (Cross-Platform-Notifications and localized-notifications) 中了解到,templates 将让我实现这一点。

我的问题

  1. 如何使用安装完成模板注册?
  2. 模板必须是什么样子才能在客户端本地化?客户端必须做什么才能实现本地化? (或者是否有每个语言环境的模板?)
  3. 不知道客户端平台或语言环境的情况下,后端必须做什么才能发送通知?
  4. 我有不同的消息(文本)要发送。每条消息都需要一个(甚至更多)模板吗?

要回答1-3,你会想看看Template feature. (Q1) Since you are using Mobile Apps, the Mobile Apps Xamarin SDKs actually allows you to register with templates in Installations directly. (Q2) To see what a template looks like in an Installation object, the body here是个好地方。 (Q3) 要发送,您链接到的教程实际上提供了很好的示例。 对于第四季度,这真的取决于。您可以使用相同的模板来传达不同的消息,因为使用此模板注册的所有用户都会收到这些消息(例如,在 cross-plat tutorial 中,您可以轻松地切换到 "Hello,"+ 用户并使用另一条消息)。但是如果您需要将这些消息本地化等,您将需要多个模板。

如果您有任何其他问题,请告诉我。

我找到了实现所需行为的解决方案。

出于演示目的,假设客户端可以注册两个不同的通知,MessageA 和 MessageB。 MessageA 从客户端标记为 "tagForMessageA",MessageB 从客户端标记为 "taggedForMessageB" 。当客户端应用程序启动或用户更改其语言时,它会调用 web-API 并为其要接收的每条消息指定 one 模板(本例中为 messageA 和 messageB) .正文包含 平台特定的本地化正文 ,例如:

MessageA, 英文iOS

{"aps":{"alert":"This is message A!"}}

MessageB,德语 android

{"data":{"message":"Dies ist NachrichtB für Android!"}}

这使客户能够决定

  • 它想要接收什么消息
  • 消息使用的语言
  • 如何显示它们。

通过API

注册

现在这是处理注册的 web-API 代码:

API 控制器

[HttpPut]
[Route("")]
public async Task<IHttpActionResult> CreateOrUpdateDeviceInstallation(DeviceInstallationModel deviceInstallationModel)
{
    var installation = new Installation
    {
        InstallationId = deviceInstallationModel.InstallationId,
        PushChannel = deviceInstallationModel.Handle,
        Tags = new List<string>
        {
            //Obtain the users id from the database here
        },
        Templates = new Dictionary<string, InstallationTemplate>()
    };
    switch (deviceInstallationModel.Platform)
    {
        case "apns":
            installation.Platform = NotificationPlatform.Apns;
            break;
        case "gcm":
            installation.Platform = NotificationPlatform.Gcm;
            break;
        default:
            return BadRequest("The given platform is not supported");
    }
    foreach (var templateModel in deviceInstallationModel.Templates)
    {
        if (installation.Templates.ContainsKey(templateModel.MessageIdentifier))
        {
            return BadRequest("Message identifiers must be unique");
        }
        installation.Templates.Add(
            templateModel.MessageIdentifier,
            CreateInstallationTemplateFromModel(templateModel));
    }
    await _notificationHubClient.CreateOrUpdateInstallationAsync(installation);

    return Ok();
}

private static InstallationTemplate CreateInstallationTemplateFromModel(TemplateModel templateModel)
{
    return new InstallationTemplate
    {
        Body = templateModel.Body,
        Tags = new List<string> {templateModel.MessageIdentifier}
    };
}

型号

public class DeviceInstallationModel
{
    public DeviceInstallationModel()
    {
        Templates= new List<TemplateModel>();
    }

    public string InstallationId { get; set; }
    public string Platform { get; set; }
    public string Handle { get; set; }
    public List<TemplateModel> Templates { get; set; }
}

public class TemplateModel
{
    public string MessageIdentifier { get; set; }

    public string Body { get; set; }
}

消息标识符

这是客户也必须遵守的约定:

public class MessageIdentifiers
{
    public const string MessageA = "tagForMessageA";
    public const string MessageB = "tagForMessageB";
}

从后端发送消息

此代码处理向客户端发送通知

消息A

public void SendMessageA(int recipientUserId)
{
    var tagExpression = $"{recipientUserId}&&{MessageIdentifiers.MessageA}";
    _notificationHubClient.SendTemplateNotificationAsync(new Dictionary<string, string>(),
            tagExpression);
}

消息B

public void SendMessageB(int recipientUserId)
{
    var tagExpression = $"{recipientUserId}&&{MessageIdentifiers.MessageB}";
    _notificationHubClient.SendTemplateNotificationAsync(new Dictionary<string, string>(),
            tagExpression);
}
  1. How is the template registration done using Installations?

正如您已经在自己的答案中使用的那样,使用 Templates property of the Installation class.

  1. How must a template look like in order to be localizable on the client and what must a client do to achieve localization? (Or is there a template per locale?)

对需要本地化的文本使用模板参数,并为参数名称添加语言后缀。更准确地说,客户应该使用带有语言后缀参数的模板进行注册。

iOS 英语语言环境示例:

{"aps":{"alert":"$(message_en)"}}

Android 德语语言环境示例:

{"data":{"message":"$(message_de)"}}
  1. What must the backend do to send notifications while not knowing the clients platform or locale?

只需在所有可能的语言环境中发送包含所有参数的模板通知。

假设应用程序仅支持英语和德语的示例:

public void SendMessageA(int recipientUserId)
{
    var tagExpression = $"{recipientUserId}";
    var parameters = new Dictionary<string, string>()
    {
        { "message_en", "This is message A!" },
        { "message_de", "Dies ist Nachricht A!" }
    };

    _notificationHubClient.SendTemplateNotificationAsync(parameters, tagExpression);
}

public void SendMessageB(int recipientUserId)
{
    var tagExpression = $"{recipientUserId}";
    var parameters = new Dictionary<string, string>()
    {
        { "message_en", "This is message B!" },
        { "message_de", "Dies ist Nachricht B!" }
    };

    _notificationHubClient.SendTemplateNotificationAsync(parameters, tagExpression);
}
  1. I have different messages (text) to send. Do I need one (or even more) templates for each message?

如您所见,通过这种方法,您可以为每个应用程序实例注册一个模板,并可以从后端发送不同的本地化消息。

当然,你的答案中的方法也有效,但你应该尽可能避免使用标签,因为标签表达式是有限的(例如 to 6 tags, if the expression contains other operators than OR),如果你不这样做,你会更灵活将通知文本硬编码到您的应用中。