Windows の Graph 通知クライアント側 SDK を使用すると、Windows UWP アプリは、必要な登録手順を実行して、ユーザーをターゲットにしてアプリ サーバーから発行された通知を受信する受信エンドポイントになることができます。 その後は、このクライアントに到着した新しい通知ペイロードの受信、通知の状態の管理、通知履歴の取得など、クライアント側で通知を管理するためにこの SDK を使用します。 MS Graph 通知の詳細と、それによって人間が主体の通知配信が実現するしくみについては、Microsoft Graph 通知の概要に関するページを参照してください
通知のシナリオに関連したリファレンス ドキュメントへのリンクは、API リファレンスのページを参照してください。
Connected Devices Platform にアクセスして Graph 通知を使用するための準備段階のセットアップ
Graph 通知と統合するために、いくつかの手順を実行する必要があります。
- MSA または AAD アプリ登録
- クロスプラットフォームのアプリ ID とプッシュ通知資格情報を提供するためのデベロッパー センターでのオンボーディング
- SDK の追加と Connected Devices Platform の初期化
- 通知サービスと Connected Devices Platform の関連付け
まず、MSA/AAD アプリ登録を完了する必要があります。 これが既に完了している場合、次のセクションに進みます。
MSA および AAD 認証登録
Microsoft アカウント (MSA) または Azure Active Directory (AAD) 認証登録は、近距離共有 API を除いた、通知を含む SDK のすべての機能に必要です。
MSA をまだ所有しておらず、使用したい場合は、account.microsoft.com で登録してください。
次に、ユーザー用の認証および ID フレームワークとして MSA を使用している場合、アプリケーション登録ポータルの指示に従って、アプリを Microsoft に登録する必要があります (Microsoft 開発者アカウントを所有していない場合は、最初に作成する必要があります)。 アプリのクライアント ID 文字列が届くはずです。必ず、場所を覚えておくか保存しておいてください。 これは後で Graph 通知のオンボーディング中に使用されます。
次に示すように、MSA 認証を使用するアプリは Live SDK アプリケーションとして登録する必要があることに注意してください。
職場アカウントまたは学校アカウントの認証および ID フレームワークとして AAD を使用するアプリを作成している場合は、次に示すように、クライアント ID を取得するために Azure Active Directory 認証ライブラリ経由でアプリを登録する必要があります。
新しいアプリ登録を作成するとき、Graph 通知やその他の Connected Devices Platform の機能を使用するために必要なアクセス許可がいくつかあります。 下記を参照してください。
- 次に示すように、ユーザーのサインインのアクセス許可を追加します。
- 次に示すように、デバイス情報に対するコマンド サービスのアクセス許可を追加します。
- 次に示すように、アクティビティ フィード サービス API の下に Graph 通知のアクセス許可を追加します。
- 最後に、Windows で動作する UWP アプリを含むクロスプラットフォーム アプリケーションを作成している場合は、次に示すように、Windows 通知サービスのアクセス許可を必ず追加してください。
次に、Graph 通知の使用などのクロスデバイス エクスペリエンスと統合するために、Microsoft Windows デベロッパー センターでオンボーディングを行い、Connected Device Platform にアクセスできるようにする必要があります。 これが既に完了している場合、次のセクションに進みます。
Microsoft Windows デベロッパー センターでクロスデバイス エクスペリエンスのためにアプリを登録する
次に、Microsoft デベロッパー ダッシュボードのクロスデバイス エクスペリエンス機能用にアプリを登録する必要があります。 これは、上記の手順で説明した MSA および AAD アプリ登録とは異なる手続きです。 このプロセスの主な目的は、プラットフォーム固有のアプリ ID を、Connected Devices Platform によって認識されるクロスプラットフォームのアプリ ID にマップすること、またそれと同時に、Microsoft Graph 通知において、各 OS プラットフォームに対応したネイティブのプッシュ通知サービスを使用して通知を送信するのを認可することです。 この場合は、Graph 通知が WNS (Windows 通知サービス) 経由で Windows UWP アプリ エンドポイントに通知を送信できるようにします。
次に示すように、デベロッパー センターのダッシュボードに移動し、左側のナビゲーション ウィンドウから [Cross-Device Experiences] (クロスデバイス エクスペリエンス) に移動して、[configuring a new cross-device app] (新しいクロスデバイス アプリの構成) を選択します。
デベロッパー センターのオンボーディング プロセスでは、次の手順が必要です。
サポートされているプラットフォームの選択 – アプリがプレゼンスを持ち、クロスデバイス エクスペリエンスが有効化されるプラットフォームを選択します。 Graph 通知との統合の場合、Windows、Android、iOS から選択できます。 次のように表示されます。
アプリ ID の指定 – アプリがプレゼンスを持っているプラットフォームごとにアプリ ID を指定します。 次のように表示されます。
注意
プラットフォームごとに (最大 10 個の) 異なる ID を追加できます。これは、同じアプリの複数のバージョン、または複数の異なるアプリがあり、同じユーザーをターゲットにしてアプリ サーバーから送信された同じ通知をこれらのアプリで受信できるようにしたい場合です。
- MSA/AAD アプリ登録のアプリ ID を指定または選択します。 MSA または AAD アプリ登録に対応するこれらのクライアント ID は、前述した以前の MSA/AAD アプリ登録手順で取得しました。 次のように表示されます。
- Graph 通知やその他の Connected Devices Platform の機能は、主要プラットフォームの各ネイティブ通知プラットフォーム、具体的には WNS (Windows UWP)、GCM (Android)、および APNS (iOS) を利用してアプリ クライアント エンドポイントに通知を送信します。 ユーザーをターゲットにした通知を発行したときに Graph 通知がアプリ サーバーの通知を配信できるよう、これらの通知プラットフォームの資格情報を指定します。 次のように表示されます。
注意
Windows UWP アプリの場合、WNS プッシュ通知の有効化は、Microsoft Graph 通知を使用するための前提条件です。 詳細については、WNS の概要に関する記事を参照してください。 オンボーディングが完了したら、Windows デベロッパー センターから Connected Device Platform にプッシュ資格情報を提供できるようになります。
- 最後の手順では、クロスデバイス アプリ ドメインを検証します。これには、登録したアプリのクロスデバイス アプリ ID のように機能するこのドメインの所有権をアプリが持っていることを証明する検証プロセスとしての役割があります。 次のように表示されます。
これで、オンボーディングの準備は万端です! 次のセクションに進んでください。
次に、Project Rome SDK をプロジェクトに追加して、Connected Devices Platform を初期化する必要があります。 これが既に完了している場合、次のセクションに進みます。
SDK の追加
次のリポジトリ参照を、プロジェクトのルートにある build.gradle ファイルに挿入します。
allprojects {
repositories {
jcenter()
maven { url 'https://maven.google.com' }
maven { url 'https://projectrome.bintray.com/maven/' }
}
}
続いて、次の依存関係を、プロジェクト フォルダーにある build.gradle ファイルに挿入します。
dependencies {
...
implementation 'com.microsoft.connecteddevices:connecteddevices-sdk:0.11.0'
}
アプリで ProGuard を使用する場合は、これらの新しい API 用の ProGuard 規則を追加します。 proguard-rules.txt という名前のファイルをプロジェクトの App フォルダーに作成し、ProGuard_Rules_for_Android_Rome_SDK.txt の内容を貼り付けます。
プロジェクトの AndroidManifest.xml ファイルで、<manifest>
要素の内側に次のアクセス許可を追加します (まだ存在しない場合)。 これにより、インターネットに接続して、デバイスで Bluetooth 検出を有効にするためのアクセス許可がアプリに付与されます。
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
注意
Bluetooth 関連のアクセス許可は、Bluetooth 検出を使用するために必要なだけであり、Connected Devices Platform の他の機能には必要ありません。 また、ACCESS_COARSE_LOCATION
は Android SDK 21 以降でのみ必要です。 Android SDK 23 以降では、開発者はユーザーにプロンプトを表示して実行時に位置情報へのアクセスを許可する必要もあります。
次に、Connected Devices 機能を追加するアクティビティ クラスに移動します。 connecteddevices 名前空間をインポートします。
import com.microsoft.connecteddevices.*;
実装するシナリオによっては、すべての名前空間が必要とは限りません。 将来、他の Android ネイティブ名前空間の追加が必要になる場合があります。
Connected Devices Platform の初期化
Connected Devices の機能を使用できるようになる前に、アプリ内でプラットフォームを初期化する必要があります。 他の Connected Devices のシナリオが実行可能になる前に初期化手順が必要なため、main クラスの onCreate または onResume メソッドで初期化手順を実行する必要があります。
Platform クラスをインスタンス化する必要があります。 Platform のコンストラクターは、アプリの Context、NotificationProvider、および UserAccountProvider の 3 つのパラメーターを取ります。
NotificationProvider パラメーターは特定のシナリオでのみ必要です。 Microsoft Graph の通知を使用する場合は必須です。 今は null
のままにしておきます。ネイティブのプッシュ チャネル経由で受信したユーザー向けの通知をクライアント SDK で処理できるようにする方法について、次のセクションで確認してください。
UserAccountProvider は、Connected Devices Platform への現在のユーザーのアクセスのための OAuth 2.0 アクセス トークンを配信するために必要です。 これは、アプリの初回実行時と、プラットフォーム管理の更新トークンの有効期限が切れたときに呼び出されます。
プラットフォームへの開発者のオンボーディングがもっと簡単になるよう、Android および iOS 用のアカウント プロバイダーの実装を提供しています。 認証プロバイダーのサンプルにあるこれらの実装を使用して、アプリ用の OAuth 2.0 アクセス トークンおよび更新トークンを取得できます。
認証とアカウント管理の設定
Connected Devices Platform では、有効な OAuth トークンを登録プロセスで使用する必要があります。 OAuth トークンの生成および管理には任意の方法を使用できます。 ただし、プラットフォームを初めて使用する開発者を支援し、利便性を高めるために、更新トークンを生成および管理する認証プロバイダーを Android サンプルアプリの一部として含めています。
ConnectedDevicesAccountManager インターフェイスを独自に実装する場合は、次の情報に留意してください。
MSA を使用している場合、サインイン要求に次のスコープを含める必要があります: "wl.offline_access"
、"ccs.ReadWrite"
、"dds.read"
、"dds.register"
、"wns.connect"
、"asimovrome.telemetry"
、および "https://activity.windows.com/UserActivity.ReadWrite.CreatedByApp"
。
AAD アカウントを使用している場合、次の対象ユーザーを要求する必要があります: "https://cdpcs.access.microsoft.com"
、"https://cs.dds.microsoft.com"
、"https://wns.windows.com/"
、および "https://activity.microsoft.com"
。
注意
Azure Active Directory (AAD) アカウントは、Device Relay API ではサポートされていません。
提供されている ConnectedDevicesAccountManager の実装を使用するかどうかにかかわらず、AAD を使用している場合は、Azure portal のアプリの登録 (portal.azure.com > [Azure Active Directory] > [アプリの登録]) で次のアクセス許可を指定する必要があります。
- Microsoft アクティビティ フィード サービス
- このアプリのユーザー通知を配信および変更する
- アプリのアクティビティを読み取ってユーザーのアクティビティ フィードに書き込む
- Windows 通知サービス
- デバイスを Windows 通知サービスに接続する
- Microsoft Device Directory Service
- デバイスの一覧を参照する
- デバイスとアプリの一覧に追加される
- Microsoft Command Service
- ユーザー デバイスと通信する
- ユーザー デバイスを読み取る
次のコードでは、mSignInHelper
は MSAAccountProvider を参照し、これも続けて初期化されます。 この提供されたクラスは UserAccountProvider インターフェイスを実装します。
private MSAAccountProvider mSignInHelper;
// ...
// Create sign-in helper from helper lib, which does user account and access token management for us
// Takes two parameters: a client id for msa, and the Context
mSignInHelper = new MSAAccountProvider(Secrets.MSA_CLIENT_ID, getContext());
// add an event listener, which changes the button text when account state changes
mSignInHelper.addUserAccountChangedListener(new EventListener<UserAccountProvider, Void>() {
@Override
public void onEvent(UserAccountProvider provider, Void aVoid){
if (mSignInHelper.isSignedIn()) {
// update the UI indicating a user is signed in.
}
else
{
// update the UI indicating a user is not signed in.
}
}
});
ここで、Platform インスタンスを作成できます。 独立したヘルパー クラスに次のコードを配置したい場合があります。
// Platform helper class:
private static Platform sPlatform;
//...
// This is the main Platform-generating method
public static synchronized Platform getOrCreatePlatform(Context context, UserAccountProvider accountProvider, NotificationProvider notificationProvider) {
// check whether the local platform variable is already initialized.
Platform platform = getPlatform();
if (platform == null) {
// if it is not initialized, do so:
platform = createPlatform(context, accountProvider, notificationProvider);
}
return platform;
}
// gets the local platform variable
public static synchronized Platform getPlatform() {
return sPlatform;
}
// creates and returns a new Platform instance
public static synchronized Platform createPlatform(Context context, UserAccountProvider accountProvider, NotificationProvider notificationProvider) {
sPlatform = new Platform(context, accountProvider, notificationProvider);
return sPlatform;
}
main クラスで、mSignInHelper
が初期化される位置に次のコードを追加します。
private Platform mPlatform;
//...
mPlatform = PlatformHelperClass.getOrCreatePlatform(this, mSignInHelper, null);
アプリがフォアグラウンドを終了したら、プラットフォームをシャットダウンする必要があります。
mPlatform.shutdownAsync();
最後に、アプリでのプッシュ通知の受信を有効化する必要があります。 これが既に完了している場合、次のセクションに進みます。
Connected Devices Platform を各モバイル プラットフォームのネイティブのプッシュ通知に関連付けます。
既に触れたように、アプリ クライアントは、登録プロセスの間、各モバイル プラットフォームで使用されているネイティブのプッシュ通知パイプラインに関する情報を、クライアント側 SDK と Connected Devices Platform に提供する必要があります。これは、ユーザーをターゲットにした通知をアプリ サーバーが Microsoft Graph API を使って発行したときに、Graph の通知サービスが個々のアプリ クライアント エンドポイントに通知を拡散できるようにするためです。
上記の手順では、null
notificationProvider パラメーターを使用してプラットフォームを初期化しました。 ここでは、NotificationProvider を実装するオブジェクトを作成して渡す必要があります。 主な注意点は、getNotificationRegistrationAsync
メソッドが NotificationRegistration インスタンスを返す必要があることです。
NotificationRegistration の役割は、通知サービス用のアクセス トークン (および関連情報) を Connected Devices Platform に提供することです。
private NotificationRegistration mNotificationRegistration;
// ...
/**
* NotificationRegistration is constructed with four parameters:
* Type: This is the notification platform type.
* Token: This is the string that GCM or FCM sends to your registration intent service.
* SenderId: This is the numeric Sender ID that you received when you registered your app for push notifications.
* DisplayName: This should be the name of the app that you used when you registered it on the Microsoft dev portal.
*/
mNotificationRegistration = new NotificationRegistration(NotificationType.FCM, token, FCM_SENDER_ID, "MyAppName");
NotificationProvider の実装でこの登録を配信します。 次に、Platform の初期化呼び出しで、プッシュ通知サービスへのアクセスをローカルの Platform に提供して、サーバー側の Microsoft Graph 通知からアプリがデータを受信できるようにする必要があります。
着信プッシュ通知をクライアント SDK に渡す
ここで、 メソッド (通知処理メソッド) の特殊なオーバーロードによって、ネイティブ リスナー サービス クラス (この場合は onMessageReceived
。このチュートリアルでは Firebase Cloud Messaging を使用するため) を拡張することだけです。
コンプライアンス、セキュリティ、潜在的な最適化のため、サーバー側の Graph 通知から受信する Google Cloud Messaging 通知は、アプリ サーバーによって最初に公開される一切のデータを含まないショルダー タップである可能性があります。 アプリ サーバーによって発行された実際の通知内容の取得は、クライアント側の SDK API の背後に隠されています。 このため SDK は、アプリ クライアントが常に、受信した Google Cloud Messaging ペイロードを SDK に渡すという一貫したプログラミング パターンを提供できます。 これによって SDK は、(Android のネイティブ Google Cloud Messaging チャネルが他の目的のためにアプリ クライアントによって使用されている場合に) これが Connected Device Platform のシナリオ向けの通知であるかどうか、また、この受信した通知はどのシナリオや機能 (Graph 通知、ユーザー アクティビティ、その他) に対応しているのかを判断できます。 その後、さまざまな種類のシナリオの処理に関する特定のロジックをアプリ クライアントによって実行できます。
/**
* Check whether it's a Connected Devices Platform notification or not.
* If it is a Connected Devices Platform notification, it will notify the apps with the information in the notification.
* @param from describes message sender.
* @param data message data as String key/value pairs.
*/
@Override
public void onMessageReceived(String from, Bundle data) {
Log.d(TAG, "From: " + from);
// Ensure that the Platform is initialized here before going on
// ...
// This method passes the data to the Connected Devices Platform if is compatible.
if (!NotificationReceiver.Receive(data)) {
// a value of false indicates a non-Rome notification
Log.d(TAG, "GCM client received a message that was not a Rome notification");
}
}
アプリで Connected Devices Platform からの通知を処理できるようになりました。
Graph 通知チャネルの初期化
大まかに言えば、Graph 通知、ユーザー アクティビティなど、さまざまな種類のユーザー データを受信および管理するために、アプリで SDK を使用してさまざまなチャネルに登録することができます。 これらはすべて UserDataFeed に格納され、同期されます。 UserNotification は、Graph 通知を介して送信される、ユーザーをターゲットにした通知に対応するクラスおよびデータ型です。 Graph 通知と統合して、アプリ サーバーによって発行された UserNotification の受信を開始するには、まず UserNotificationChannel を作成してユーザー データ フィードを初期化する必要があります。 これは、前述したプラットフォーム初期化手順のように扱う必要があります。(プラットフォーム初期化の前ではないタイミングで) アプリがフォアグラウンドになるたびにチェックし、場合によってはやり直す必要があります。
UserNotificationReader を作成して着信 UserNotification を受信し UserNotification の履歴にアクセスする
UserNotificationChannel の参照を取得したら、SDK で実際の通知内容をサーバーから取得できるようにするために UserNotificationReader が必要です。 この場合、アプリ クライアントは UserNotificationReader を使用してこのデータ フィードにアクセスし、イベント リスナーを介して最新の通知ペイロードを受信したり、ユーザーの通知履歴のビュー モデルとして使用できる完全な UserNotification コレクションにアクセスしたりできます。
次のコードは、ユーザー通知チャネルをインスタンス化し、ユーザー通知リーダーを作成し、イベント ハンドラーをユーザー通知リーダーに追加する手順を示しています。このイベント ハンドラーは、Connected Device Platform が毎回の同期を完了し、通知が必要な新しい変更があるときにトリガーされます。
public async Task SetupChannel()
{
var account = m_accoutProvider.SignedInAccount;
if (m_feed == null)
{
await Task.Run(() =>
{
lock (this)
{
if (m_feed == null)
{
m_platform = new ConnectedDevicesPlatform(m_accoutProvider, this);
Logger.Instance.LogMessage($"Create feed for {account.Id} {account.Type}");
m_feed = new UserDataFeed(account, m_platform, "graphnotifications.sample.windows.com");
m_feed.SyncStatusChanged += Feed_SyncStatusChanged;
m_feed.AddSyncScopes(new List<IUserDataFeedSyncScope>
{
UserNotificationChannel.SyncScope
});
m_channel = new UserNotificationChannel(m_feed);
m_reader = m_channel.CreateReader();
m_reader.DataChanged += Reader_DataChanged;
}
}
});
}
}
UserNotification の受信
前のセクションで、イベント リスナーをユーザー通知リーダーに追加しています。 すべての新しい通知と通知の更新をリーダーから読み取るために、このイベント リスナーを実装する必要があります。また、これらの新しい変更を個々に処理する独自のビジネス ロジックを実装する必要があります。
ヒント
このイベント リスナーは、メインのビジネス ロジックを処理し、シナリオに基づいて通知ペイロードの内容を "消費" する場所です。 現在 WNS の直接通知を使用して OS レベルのアクション センターでローカル トースト通知を作成している場合、または通知の内容を使用して何らかのアプリ内 UI を更新している場合、ここがそれらの処理を実行する場所です。
次のコードは、サンプル アプリにおいて、アクティブであるすべての着信 UserNotification に対してローカル トースト通知を発生させる方法、また、通知が削除された場合に、それに対応する通知 UI をアプリ内ビューから削除する方法を示しています。
private void Reader_DataChanged(UserNotificationReader sender, object args)
{
ReadNotifications(sender, true);
}
private async void ReadNotifications(UserNotificationReader reader, bool showToast)
{
var notifications = await reader.ReadBatchAsync(UInt32.MaxValue);
foreach (var notification in notifications)
{
if (notification.Status == UserNotificationStatus.Active)
{
m_newNotifications.RemoveAll((n) => { return (n.Id == notification.Id); });
if (notification.UserActionState == UserNotificationUserActionState.NoInteraction)
{
// new notification, show this to user using the Windows local toast notification APIs
m_newNotifications.Add(notification);
if (!string.IsNullOrEmpty(notification.Content) && showToast)
{
ShowToastNotification(BuildToastNotification(notification.Id, notification.Content));
}
}
m_historicalNotifications.RemoveAll((n) => { return (n.Id == notification.Id); });
m_historicalNotifications.Insert(0, notification);
}
else
{
// Existing notification is marked as deleted, remove from display
m_newNotifications.RemoveAll((n) => { return (n.Id == notification.Id); });
m_historicalNotifications.RemoveAll((n) => { return (n.Id == notification.Id); });
RemoveToastNotification(notification.Id);
}
}
}
既存の UserNotification の状態を更新する
前のセクションで説明しましたが、時として、リーダー経由で受信した UserNotification の変更は、既存の UserNotification の状態更新 (それが無視とマークされているか既読とマークされているかは問わない) である可能性があります。 この場合アプリ クライアントは、この特定のデバイス上で対応する視覚的通知を削除することによって全体無視を有効化するなど、実行する処理を選択できます。 少し話を戻すと、多くの場合、この UserNotification の変更更新を最初に別のデバイスから開始したのはアプリ クライアントです。 UserNotification の状態を更新するタイミングは選択できますが、それは通常、対応する視覚的通知がそのデバイス上でユーザーによって処理された時点、または、有効化する何らかのアプリ内エクスペリエンスでその通知がユーザーによってさらに処理された時点です。 フローがどのようになるかの例を次に示します: アプリ サーバーはユーザー A をターゲットに通知を発行します。ユーザー A は、アプリ クライアントがインストールされている PC と電話の両方でこの通知を受信します。 ユーザーは PC で通知をクリックし、対応するタスクを処理するためにアプリを起動します。 その後、この PC 上のアプリ クライアントが Connected Devices Platform SDK を呼び出して、対応する UserNotification の状態を更新し、このユーザーのすべてのデバイス間でこの更新を同期します。 他のアプリ クライアントは、この状態更新をリアルタイムで受信すると、対応する視覚的アラート/メッセージ/トースト通知をデバイスの通知センター/通知トレイ/アクション センターから削除します。 これは、ユーザーのデバイス間で通知が全体無視されるしくみです。
ヒント
UserNotification クラスは現在、2 種類の状態更新を提供します。UserNotificationReadState または UserNotificationUserActionState を変更し、通知が更新されたときに実行する処理について独自のロジックを定義できます。 たとえば、UserActionState を Activated (アクティブ化) または Dismissed (無視) とマークし、その値を基準にして全体無視を実装できます。 その代わりに、または同時に、ReadState を Read (既読) または Unread (未読) とマークし、それに基づいて、どの通知をアプリ内通知の履歴ビューに表示するかを決定できます。 次のコード スニペットは、通知の UserNotificationUserActionState を Dismissed とマークする方法を示しています。
public async void Dismiss(string id)
{
var notification = m_newNotifications.Find((n) => { return (n.Id == id); });
if (notification != null)
{
notification.UserActionState = UserNotificationUserActionState.Dismissed;
await notification.SaveAsync();
}
}