次の方法で共有


アプリ バックエンドからの登録

前のセクションで説明したように、プッシュ通知を受信するには、デバイスが通知ハブに 1 つ以上の登録を作成する必要があります。 この登録を完了する方法の 1 つは、モバイル デバイスに通知ハブに直接連絡して、PNS ハンドルとそのタグを指定 (または更新) してもらう方法です。 この方法にはいくつかの制限があり、デバイスが登録を更新するときに独自のアプリ バックエンドに連絡することが推奨されるシナリオがいくつかあります。 その後、バックエンドは通知ハブを呼び出します。

アプリ バックエンドから登録するタイミング

アプリ バックエンドを介してデバイス登録をルーティングすることをお勧めするシナリオは 2 つあります。

タグをセキュリティで保護する必要がある

デバイスは、通知ハブに直接登録するときに、必要な任意のタグを指定できます。 タグが任意のデバイスがサブスクライブできる公共の利益グループ (スポーツ チームに関するニュース フィードなど) である場合、これは問題ではありません。 ただし、一部のタグが一部のユーザーのみが使用できる場合は、この問題が発生する可能性があります。

各ユーザーを許可されたタグのみに登録するには、独自のアプリ バックエンドを介して登録操作をルーティングする必要があります。これにより、ユーザー認証を実行し、必要なタグの登録を承認できます。

このシナリオの最も一般的な例は、タグを使用してユーザー ID を表します。 この場合、他のユーザーの通知を受信するため、他のユーザーを表すタグにデバイスが登録されないようにする必要があります。

タグはアプリ バックエンドによって変更されます

デバイスからの登録は便利であり、プッシュ通知と関心グループへの豊富なルーティングをすばやく設定できます。 ただし、他のデバイスで発生するイベントの結果としてタグを変更する場合は、デバイスからの登録があまりうまく機能しません。

2 つのシナリオを検討してください。Alice の電話で発生したイベントの結果として Alice の電話のタグが設定されている場合、アプリは通知ハブのタグを簡単に更新できます。 一方、他のデバイス (たとえば、Web サイトにログオンしたときに Alice のノート PC) で発生したイベントの結果としてタグを変更する必要がある場合、デバイスは通知ハブの変更を反映するために、アプリが再びアクティブになるのを待つ必要があります。

前のシナリオの具体的な例は、Web エクスペリエンスとモバイル アプリを含む音楽アプリです。 この場合、特定のユーザーが Web サイトを通じて新しいバンドをフォローし、デバイスに新しいバンドに関する通知をできるだけ早く受信するようにします。 もう 1 つの例として、バックエンドの他の部分 (CRM など) からタグが取得され、ユーザーの状態が Silver から Gold に変更される場合があります。 この変更により、すべてのユーザーの登録に新しいタグが設定される可能性があります。

バックエンドから登録する方法

デバイスを登録するときは、通知ハブで異なるデバイスを区別する必要があります。 PNS ハンドルは一時的であり、一意ではないため、PNS ハンドルを見るだけでは実現できません。 この問題を解決するために、Notification Hubs は、PNS ハンドル、タグ、またはテンプレートを更新するたびに独自の登録を参照できるようにするために、各デバイスがローカルに格納する必要がある有効期間の長い登録 ID を生成します。

次の図は、ネイティブ通知の登録フローを示しています。

  1. デバイスで、登録 ID がローカルに格納されていない場合は、

    1. 登録 ID を取得するには、アプリ バックエンドを呼び出します。

    2. アプリ バックエンドは通知ハブを呼び出して新しい登録 ID を作成し、その ID をデバイスに返します。

    3. デバイスのローカル ストレージに登録 ID をMicrosoft Storeします。

  2. デバイスで、ローカル ストレージから登録 ID を取得します。

    1. 登録 ID、PNS ハンドル、タグを指定して、アプリ バックエンドを呼び出します。

    2. アプリ バックエンドは、通知ハブで対応する登録を作成または更新します。

    3. アプリ バックエンドが状態コード 410 を返す場合は、新しい登録 ID を作成する必要があります。 登録 ID をローカル ストレージから削除し、手順 1 から再起動します。

Backend Registration

テンプレート通知のフローは似ています。 唯一の違いは次のとおりです。

  1. デバイスで複数のテンプレートを使用する場合は、テンプレートごとに 1 つの登録 ID を格納する必要があります。

  2. 登録の 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"];

        }
    }

登録 ID をバックエンド データベースに格納する

アプリケーションでは、デバイスのローカル ストレージではなく、アプリ バックエンドに登録 ID を保持することが必要な場合があります。 これは通常、アプリ バックエンドにデバイス ( installationId など) を識別する方法があり、バックエンド ストレージにデバイス情報を格納する方法がある場合 (たとえば、PNS ハンドルが格納されたカスタム プッシュ ソリューションから移行する場合) に発生します。

バックエンドからタグを変更する方法

バックエンドからタグを変更する場合は、バックエンドが変更される登録を識別する方法が必要です。 これは通常、タグを使用して行われます。

たとえば、ユーザーが Web から新しいお気に入りのバンドを追加し、その結果としてバックエンドがユーザーのモバイル登録にタグを追加する音楽アプリがあるとします。 この場合、アプリはタグを使用してユーザーを識別し、そのタグを使用して更新する登録を取得して更新します。

次のコード例では、登録を取得し、それらに新しいタグを追加します。

var registrations = await hub.GetRegistrationsByTagAsync("{userId}", 10);
            foreach (var reg in registrations)
            {
                reg.Tags.Add("{newBand}");
                await hub.UpdateRegistrationAsync(reg);
            }

この例では、テンプレートを使用している場合は、すべてのテンプレートにタグを追加していることを前提としています。