從應用程式後端註冊
如前幾節所述,裝置必須在通知中樞中建立一或多個註冊,才能接收推播通知。 完成此註冊的其中一種方法是讓行動裝置直接連絡通知中樞,以指定 (或更新其 PNS 控制碼及其標籤) 。 此方法有一些限制,而且在某些情況下,建議您在裝置重新整理註冊時連絡您自己的應用程式後端。 後端接著會呼叫通知中樞。
從應用程式後端註冊的時機
在兩個案例中,建議您透過應用程式後端路由傳送裝置註冊。
必須保護標籤
當裝置直接向通知中樞註冊時,它可以指定想要的任何標籤。 如果標籤是任何裝置可訂閱 (的公用興趣群組,例如,有關運動團隊的新聞摘要) ,則這不是問題。 不過,當某些標籤僅適用于某些使用者時,這可能會發生問題。
若要只向允許的標籤註冊每個使用者,您必須透過自己的應用程式後端路由註冊作業,以便執行使用者驗證並授權註冊所需的標籤。
此案例最常見的範例是使用標記來代表使用者識別碼。 在此情況下,您想要防止裝置註冊代表其他使用者的標籤,因為它們會收到其他使用者的通知。
標籤是由您的應用程式後端修改
從裝置註冊很方便,可讓您快速設定推播通知,以及對興趣群組的豐富路由。 不過,如果您想要因其他裝置上發生的事件而變更標籤,則從裝置註冊無法正常運作。
請考慮兩種案例:如果 Alice 手機上的標籤設定為 Alice 手機上發生事件的結果,則應用程式很容易在通知中樞更新標籤。 如果另一方面,標籤必須因為其他裝置上發生的事件而變更 (,例如,Alice 的膝上型電腦登入網站) ,則裝置必須等候應用程式再次作用中,才能反映通知中樞中的變更。
上述案例的特定範例是包含 Web 體驗和行動應用程式的音樂應用程式。 在此情況下,特定使用者可能會透過網站追蹤新的訊號範圍,並想要裝置儘快開始接收新訊號範圍的相關通知。 另一個範例是標籤來自 CRM 的其他部分 (CRM,例如) ,可將使用者的狀態從 Silver 變更為 Gold。 這項變更可能會導致在所有使用者註冊上設定新的標記。
如何從後端註冊
註冊裝置時,通知中樞必須區分不同的裝置。 這無法只藉由查看 PNS 控制碼來完成,因為它們是暫時性且不是唯一的。 為了解決此問題,通知中樞會產生長期註冊識別碼,讓每個裝置都必須儲存在本機,才能在每次更新 PNS 控制碼、標記或範本時參考自己的註冊。
下圖顯示原生通知的註冊流程:
在裝置上,如果未在本機儲存任何註冊識別碼,則為
呼叫應用程式後端以取得註冊識別碼。
應用程式後端會呼叫通知中樞來建立新的註冊識別碼,然後將識別碼傳回給裝置。
Microsoft Store裝置本機儲存體中的註冊識別碼。
在裝置上,從本機儲存體擷取註冊識別碼:
呼叫應用程式後端,提供註冊識別碼、PNS 控制碼和標記。
應用程式後端會在通知中樞上建立或更新對應的註冊。
如果應用程式後端傳回狀態碼 410,則必須建立新的註冊識別碼。 從本機儲存體刪除註冊識別碼,然後從步驟 1 重新開機。
範本通知的流程類似。 唯一的差異如下:
如果裝置使用多個範本,則必須為每個範本儲存一個註冊識別碼。
您可以使用註冊的 TemplateName 屬性來識別範本。
下列程式碼是後端端點的範例。
public class RegisterController : ApiController
{
private NotificationHubClient hub;
public RegisterController()
{
hub = NotificationHubClient.CreateClientFromConnectionString("Endpoint=sb://buildhub-ns.servicebus.windows.net/;SharedAccessKeyName=DefaultFullSharedAccessSignature;SharedAccessKey=DuWV4SQ08poV6HZly8O/KQNWv3YRTZlExJxu3pNCjGU=", "build2014_2");
}
public class DeviceRegistration
{
public string Platform { get; set; }
public string Handle { get; set; }
public string[] Tags { get; set; }
}
// POST api/register
// This creates a registration id
public async Task<string> Post()
{
return await hub.CreateRegistrationIdAsync();
}
// PUT api/register/5
// This creates or updates a registration (with provided PNS handle) at the specified id
public async void Put(string id, DeviceRegistration deviceUpdate)
{
// IMPORTANT: add logic to make sure that caller is allowed to register for the provided tags
RegistrationDescription registration = null;
switch (deviceUpdate.Platform)
{
case "mpns":
registration = new MpnsRegistrationDescription(deviceUpdate.Handle);
break;
case "wns":
registration = new WindowsRegistrationDescription(deviceUpdate.Handle);
break;
case "apns":
registration = new AppleRegistrationDescription(deviceUpdate.Handle);
break;
case "gcm":
registration = new GcmRegistrationDescription(deviceUpdate.Handle);
break;
default:
throw new HttpResponseException(HttpStatusCode.BadRequest);
}
registration.RegistrationId = id;
registration.Tags = new HashSet<string>(deviceUpdate.Tags);
try
{
await hub.CreateOrUpdateRegistrationAsync(registration);
} catch (MessagingException e) {
ReturnGoneIfHubResponseIsGone(e);
}
}
// DELETE api/register/5
public async void Delete(string id)
{
await hub.DeleteRegistrationAsync(id);
}
private static void ReturnGoneIfHubResponseIsGone(MessagingException e)
{
var webex = e.InnerException as WebException;
if (webex.Status == WebExceptionStatus.ProtocolError)
{
var response = (HttpWebResponse)webex.Response;
if (response.StatusCode == HttpStatusCode.Gone)
throw new HttpRequestException(HttpStatusCode.Gone.ToString());
}
}
}
請注意,在上述程式碼中,您必須新增邏輯,以確保呼叫該端點的用戶端有權註冊要求的標籤。 此外,您的後端可以新增標籤本身 (例如 userid 標籤) 。
下列程式碼範例示範如何使用上述端點,從裝置實作Windows Microsoft Store應用程式的註冊方法:
class RegisterClient
{
private string POST_URL = "{your back-end endpoints}";
private class DeviceRegistration
{
public string Platform { get; set; }
public string Handle { get; set; }
public string[] Tags { get; set; }
}
public async Task RegisterAsync(string handle, IEnumerable<string> tags)
{
var regId = await RetrieveRegistrationIdOrRequestNewOneAsync();
var deviceRegistration = new DeviceRegistration
{
Platform = "wns",
Handle = handle,
Tags = tags.ToArray<string>()
};
var statusCode = await UpdateRegistrationAsync(regId, deviceRegistration);
if (statusCode == HttpStatusCode.Gone)
{
// regId is expired, deleting from local storage & recreating
var settings = ApplicationData.Current.LocalSettings.Values;
settings.Remove("__NHRegistrationId");
regId = await RetrieveRegistrationIdOrRequestNewOneAsync();
statusCode = await UpdateRegistrationAsync(regId, deviceRegistration);
}
if (statusCode != HttpStatusCode.Accepted)
{
// log or throw
}
}
private async Task<HttpStatusCode> UpdateRegistrationAsync(string regId, DeviceRegistration deviceRegistration)
{
using (var httpClient = new HttpClient())
{
var putUri = POST_URL + "/" + regId;
var response = await httpClient.PutAsJsonAsync<DeviceRegistration>(putUri, deviceRegistration);
return response.StatusCode;
}
}
private async Task<string> RetrieveRegistrationIdOrRequestNewOneAsync()
{
var settings = ApplicationData.Current.LocalSettings.Values;
if (!settings.ContainsKey("__NHRegistrationId"))
{
using (var httpClient = new HttpClient())
{
var response = await httpClient.PostAsync(POST_URL, new StringContent(""));
if (response.IsSuccessStatusCode)
{
string regId = await response.Content.ReadAsStringAsync();
regId = regId.Substring(1, regId.Length - 2);
settings.Add("__NHRegistrationId", regId);
}
else
{
throw new Exception();
}
}
}
return (string)settings["__NHRegistrationId"];
}
}
將註冊識別碼儲存在後端資料庫中
有時候,應用程式想要將註冊識別碼保留在應用程式後端,而不是在裝置本機儲存體中。 例如,當應用程式後端已經能夠識別裝置 (例如 installationId) ,以及從 PNS 控制碼儲存) 的自訂推送解決方案移轉時,將裝置資訊儲存在後端儲存體 (時,通常會發生這種情況。
如何從後端修改標籤
如果您想要從後端修改標籤,則必須讓後端識別要修改的註冊。 這通常是使用 標記來完成。
例如,假設有一個音樂應用程式,其中使用者從 Web 新增了一個新的我的最愛的訊號,而後端會在使用者的行動註冊中新增標籤,因此。 在此情況下,應用程式會使用 標記來識別使用者,然後使用該標籤來擷取要更新並更新的註冊。
下列程式碼範例會擷取註冊,並將新的標記加入其中。
var registrations = await hub.GetRegistrationsByTagAsync("{userId}", 10);
foreach (var reg in registrations)
{
reg.Tags.Add("{newBand}");
await hub.UpdateRegistrationAsync(reg);
}
請注意,在此範例中,如果您使用範本,我們假設您要在所有範本上新增 標籤。