次の方法で共有


使い方ガイド: Graph 通知との統合 (Android)

Graph 通知を使用すると、アプリはユーザーをターゲットにした通知を複数のデバイスにまたがって送信および管理できます。

Android 上の Project Rome クライアント側 SDK によって、Android アプリは、ログイン中のユーザーをターゲットにしてアプリ サーバーから発行された通知を受信するための登録ができます。 アプリ クライアントは SDK を使用して、新しい着信通知ペイロードを受信したり、既存の通知の状態を管理したり、通知履歴を取得したりできます。 通知の詳細と、それによって人間が主体の通知配信が実現するしくみについては、Microsoft Graph 通知の概要に関するページを参照してください

Graph 通知などを含む Project Rome SDK のすべての機能は、Connected Devices Platform と呼ばれる基盤プラットフォーム上に構築されています。 このガイドの目的は、Connected Devices Platform を初めて使用するために必要な手順、および、Graph 通知に固有の機能を実装するために SDK で API を使用する方法について説明することです。

通知のシナリオに関連したリファレンス ドキュメントへのリンクは、API リファレンスのページを参照してください。

この手順では、Project Rome Android サンプル アプリのコードを参照します。

Connected Devices のすべての機能には、Android アプリ開発 IDE と、サポートされているアーキテクチャ (armeabi-v7aarm64-v8ax86、または x86_64) のいずれかを搭載した Android デバイス、またはエミュレーターが必要です。 システムで Android 4.4.2 またはそれ以降を実行している必要があります。

Connected Devices Platform と通知の準備段階のセットアップ

リモート接続を実装する前に、いくつかの手順を実行して、リモート デバイスへの接続機能と通知の送受信機能を Android アプリに提供する必要があります。

アプリの登録

Microsoft アカウント (MSA) または Azure Active Directory (AAD) 認証は、Project Rome SDK のほとんどすべての機能に必要です (例外は近距離共有 API です)。 MSA をまだ所有しておらず、使用したい場合は、account.microsoft.com で登録してください。

注意

Azure Active Directory (AAD) アカウントは、Device Relay API ではサポートされていません。

選択した認証方法を使用して、またアプリケーション登録ポータルの指示に従ってアプリを Microsoft に登録する必要があります。 Microsoft 開発者アカウントがない場合、作成する必要があります。

MSA を使用してアプリを登録したら、クライアント ID 文字列が届くはずです。 これは後で使用しますので、保存しておいてください。 これにより、アプリが Microsoft の Connected Devices Platform リソースにアクセスできるようになります。 AAD を使用している場合は、クライアント ID 文字列を取得する手順について「Azure Active Directory 認証ライブラリ」を参照してください。

SDK の追加

次のリポジトリ参照を、プロジェクトのルートにある build.gradle ファイルに挿入します。

allprojects {
    repositories {
        jcenter()
    }
}

続いて、次の依存関係を、プロジェクト フォルダーにある build.gradle ファイルに挿入します。

dependencies { 
    ...
    implementation 'com.microsoft.connecteddevices:connecteddevices-sdk:+'
}

プロジェクトの AndroidManifest.xml ファイルで、<manifest> 要素の内側に次のアクセス許可を追加します (まだ存在しない場合)。 これにより、インターネットに接続して、デバイスで Bluetooth 検出を有効にするためのアクセス許可がアプリに付与されます。

Bluetooth 関連のアクセス許可は、Bluetooth 検出を使用するために必要なだけであり、Connected Devices Platform の他の機能には必要ないことに注意してください。 また、ACCESS_COARSE_LOCATION は Android SDK 21 以降でのみ必要です。 Android SDK 23 以降では、開発者はユーザーにプロンプトを表示して実行時に位置情報へのアクセスを許可する必要もあります。

<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" />

次に、Connected Devices 機能を有効にするアクティビティ クラスに移動します。 次のパッケージをインポートします。

import com.microsoft.connecteddevices;
import com.microsoft.connecteddevices.remotesystems;
import com.microsoft.connecteddevices.remotesystems.commanding;

認証とアカウント管理の設定

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 デバイス ディレクトリ サービス
    • デバイスの一覧を参照する
    • デバイスとアプリの一覧に追加される
  • Microsoft コマンド サービス
    • ユーザー デバイスと通信する
    • ユーザー デバイスを読み取る

アプリケーションをプッシュ通知に登録する

Firebase Cloud Messaging のサポートのために、アプリケーションを Google に登録します。 受け取った送信者 ID とサーバー キーは、後で必要になるので必ずメモしておいてください。

登録したら、アプリ内で、プッシュ通知機能を Connected Devices Platform に関連付ける必要があります。

mNotificationRegistration = new ConnectedDevicesNotificationRegistration();
mNotificationRegistration.setType(ConnectedDevicesNotificationType.FCM);
mNotificationRegistration.setToken(token);
mNotificationRegistration.setAppId(Secrets.FCM_SENDER_ID);
mNotificationRegistration.setAppDisplayName("SampleApp");

Microsoft Windows デベロッパー センターでクロスデバイス エクスペリエンスのためにアプリを登録する

重要

この手順は、Project Rome の機能を使用して非 Windows デバイスからデータにアクセスする、またはそのデバイスの要求を実行する場合にのみ必要です。 Windows デバイスのみをターゲットにする場合、この手順を完了する必要はありません。

次に示すように、デベロッパー センターのダッシュボードに移動し、左側のナビゲーション ウィンドウから [Cross-Device Experiences] (クロスデバイス エクスペリエンス) に移動して、[configuring a new cross-device app] (新しいクロスデバイス アプリの構成) を選択します。 デベロッパー センター ダッシュボード – クロスデバイス エクスペリエンス

デベロッパー センターのオンボーディング プロセスでは、次の手順が必要です。

  • サポートされているプラットフォームの選択 – アプリがプレゼンスを持ち、クロスデバイス エクスペリエンスが有効化されるプラットフォームを選択します。 Graph 通知との統合の場合、Windows、Android、iOS から選択できます。 クロスデバイス エクスペリエンス – サポートされているプラットフォーム

  • アプリ ID の指定 – アプリがプレゼンスを持っているプラットフォームごとにアプリ ID を指定します。 Android アプリの場合、これはプロジェクト作成時にアプリに割り当てたパッケージ名です。 パッケージ名は、Firebase コンソールで [Project Overview](プロジェクトの概要) -> [General](全般) から確認できます。 プラットフォームごとに (最大 10 個の) 異なる ID を追加できます。これは、同じアプリの複数のバージョン、または複数の異なるアプリがあり、同じユーザーをターゲットにしてアプリ サーバーから送信された同じ通知をこれらのアプリで受信できるようにしたい場合です。 クロスデバイス エクスペリエンス – アプリ ID

  • MSA/AAD アプリ登録のアプリ ID を指定または選択します。 MSA または AAD アプリ登録に対応するこれらのクライアント ID は、前述した以前の MSA/AAD アプリ登録手順で取得しました。 クロスデバイス エクスペリエンス – MSA および AAD アプリ登録

  • Graph 通知やその他の Connected Devices Platform の機能は、主要プラットフォームの各ネイティブ通知プラットフォーム、具体的には WNS (Windows UWP)、FCM (Android)、および APNS (iOS) を利用してアプリ クライアント エンドポイントに通知を送信します。 ユーザーをターゲットにした通知を発行したときに Graph 通知がアプリ サーバーの通知を配信できるよう、これらの通知プラットフォームの資格情報を指定します。 Android の場合、Cloud Messaging サービスの有効化が、Microsoft Graph 通知を使用するための前提条件です。 また、必要な送信者 ID は Firebase Cloud Messaging の Sender ID に対応し、API キーは Legacy Server Key (従来のサーバー キー) に対応することに注意してください。 スクリーンショットに示すように、どちらも Firebase コンソール -> [Project](プロジェクト) -> [Settings](設定) の [Cloud Messaging] タブにあります。 クロスデバイス エクスペリエンス – プッシュ資格情報

  • 最後の手順では、クロスデバイス アプリ ドメインを検証します。これには、登録したアプリのクロスデバイス アプリ ID のように機能するこのドメインの所有権をアプリが持っていることを証明する検証プロセスとしての役割があります。 クロスデバイス エクスペリエンス – ドメインの確認

Graph 通知チャネルの初期化

Graph 通知、ユーザー アクティビティなど、さまざまな種類のユーザー データを受信および管理するために、アプリで Project Rome SDK を使用してさまざまなチャネルに登録することができます。 これらはすべて UserDataFeed に格納され、同期されます。 UserNotification は、Graph 通知を介して送信される、ユーザーをターゲットにした通知に対応するクラスおよびデータ型です。 Graph 通知と統合して、アプリ サーバーによって発行された UserNotification の受信を開始するには、まず UserNotificationChannel を作成してユーザー データ フィードを初期化する必要があります。 これは、前述したプラットフォーム初期化手順のように扱う必要があります。(プラットフォーム初期化の前ではないタイミングで) アプリがフォアグラウンドになるたびにチェックし、場合によってはやり直す必要があります。

次のメソッドは UserNotificationChannel を初期化します。

private UserNotificationChannel mNotificationChannel;
private UserDataFeed mUserDataFeed;

// ...

/**
 * Initializes the UserNotificationFeed.
 */
public void initializeUserNotificationFeed() {

    // define what scope of data this app needs
    SyncScope[] scopes = { UserNotificationChannel.getSyncScope() };

    // Get a reference to the UserDataFeed. This method is defined below
    mUserDataFeed = getUserDataFeed(scopes, new EventListener<UserDataFeed, Void>() {
        @Override
        public void onEvent(UserDataFeed userDataFeed, Void aVoid) {
            if (userDataFeed.getSyncStatus() == UserDataSyncStatus.SYNCHRONIZED) {
                // log synchronized.
            } else {
                // log synchronization not completed.
            }
        }
    });

    // this method is defined below
    mNotificationChannel = getUserNotificationChannel();
}

// instantiate the UserDataFeed
private UserDataFeed getUserDataFeed(SyncScope[] scopes, EventListener<UserDataFeed, Void> listener) {
    UserAccount[] accounts = AccountProviderBroker.getSignInHelper().getUserAccounts();
    if (accounts.length <= 0) {
        // notify the user that sign-in is required
        return null;
    }

    // use the initialized Platform instance, along with the cross-device app ID.
    UserDataFeed feed = UserDataFeed.getForAccount(accounts[0], PlatformBroker.getPlatform(), Secrets.APP_HOST_NAME);
    feed.addSyncStatusChangedListener(listener);
    feed.addSyncScopes(scopes);
    // sync data with the server
    feed.startSync();
    return feed;
}

// use the UserDataFeed reference to create a UserActivityChannel
@Nullable
private UserNotificationChannel getUserNotificationChannel() {
    UserNotificationChannel channel = null;
    try {
        // create a UserNotificationChannel for the signed in account
        channel = new UserNotificationChannel(mUserDataFeed);
    } catch (Exception e) {
        e.printStackTrace();
        // handle exception
    }
    return channel;
}

この時点で、UserNotificationChannel の参照が mNotificationChannel にあるはずです。

UserNotificationReader を作成して着信 UserNotification を受信し UserNotification の履歴にアクセスする

前に説明したように、アプリ クライアントに到着する初期の Google Cloud Messaging 通知にはショルダー タップしか含まれておらず、そのショルダー タップ ペイロードを Connected Devices Platform に渡して、Connected Device サーバーとの完全同期を SDK に実行させる必要があります。このサーバーには、アプリ サーバーによって発行されたすべての UserNotification が格納されます。 これにより、アプリ サーバーによって発行され、このショルダー タップに対応している完全な通知ペイロードが取得されます (また、発行されたがデバイス接続性またはその他の問題のためこのアプリ クライアントで受信されなかった以前の通知がある場合、それらも同時に取得されます)。 これらのリアルタイム同期が継続的に SDK によって実行されるので、アプリ クライアントはこのログイン中ユーザーの UserNotification データ フィードのローカル キャッシュにアクセスできます。 この場合、アプリ クライアントは UserNotificationReader を使用してこのデータ フィードにアクセスし、イベント リスナーを介して最新の通知ペイロードを受信したり、ユーザーの通知履歴のビュー モデルとして使用できる完全な UserNotification コレクションにアクセスしたりできます。

UserNotification の受信

実現しようとしているエクスペリエンスのためにその情報を利用することに関心がある場合は、まず UserNotificationReader をインスタンス化し、既にリーダーにある既存の UserNotification をすべて取得する必要があります。 この特定のデバイス エンドポイントが、ユーザーがアプリをインストールした唯一または最初のエンドポイントではない可能性を考えると、アプリ サーバーはこのログイン中ユーザーに通知を発行済みであると常に想定するのが安全です。

private static UserNotificationReader mReader;
private static final ArrayList<UserNotification> mHistoricalNotifications = new ArrayList<>();
// Instantiate UserNotificationReader
UserNotificationReaderOptions options = new UserNotificationReaderOptions();
mReader = mNotificationChannel.createReaderWithOptions(options);
// Read any previously published UserNotifications that have not expired yet
mReader.readBatchAsync(Long.MAX_VALUE).thenAccept(new AsyncOperation.ResultConsumer<UserNotification[]>() {
    @Override
    public void accept(UserNotification[] userNotifications) throws Throwable {
        synchronized (mHistoricalNotifications) {
            for (UserNotification notification : userNotifications) {
                if (notification.getReadState() == UserNotificationReadState.UNREAD) {
                    mHistoricalNotifications.add(notification);
                }
            }
        }
 
        if (RunnableManager.getHistoryUpdated() != null) {
            activity.runOnUiThread(RunnableManager.getHistoryUpdated());
        }
    }
});

ここで、Connected Devices Platform で同期が完了し、通知する新しい変更がある時点でトリガーされるイベント リスナーを追加します。 Graph 通知の場合、新しい変更として可能性があるのは、アプリ サーバーによって発行された UserNotification の新規着信、または、サーバーから発生したか同じユーザーがログインした他の登録済みエンドポイントから発生した UserNotifcation の更新、削除、期限切れです。

ヒント

このイベント リスナーは、メインのビジネス ロジックを処理し、シナリオに基づいて通知ペイロードの内容を "消費" する場所です。 現在 Google Cloud Messaging のデータ メッセージを使用して OS レベルの通知トレイで視覚的な通知を作成している場合、または通知の内容を使用して何らかのアプリ内 UI を更新している場合、ここがそれらの処理を実行する場所です。

mReader.addDataChangedListener(new EventListener<UserNotificationReader, Void>() {
    @Override
    public void onEvent(UserNotificationReader userNotificationReader, Void aVoid) {
        userNotificationReader.readBatchAsync(Long.MAX_VALUE).thenAccept(new AsyncOperation.ResultConsumer<UserNotification[]>() {
        @Override
        public void accept(UserNotification[] userNotifications) throws Throwable {
            boolean updatedNew = false;
            boolean updatedHistorical = false;
            synchronized (sHistoricalNotifications) {
                for (final UserNotification notification : userNotifications) {
                    if (notification.getStatus() == UserNotificationStatus.ACTIVE && notification.getReadState() == UserNotificationReadState.UNREAD) {
                        switch (notification.getUserActionState()) {
                            case NO_INTERACTION:
                                // Brand new notification
                                // Insert business logic to construct a new visual notification in Android notification tray for the user to see
                                // ...
                            case DISMISSED:
                                // Existing notification that is marked as dismissed
                                // An app client receive this type of changes because another app client logged in by the same user has marked the notification as dismissed and the change is fanned-out to everywhere
                                // This state sync across app clients on different devices enable universal dismiss of notifications and other scenarios across multiple devices owned by the same user
                                // Insert business logic to dismiss the corresponding visual notification inside Android system notification tray, to make sure users don’t have to deal with redundant information across devices, and potentially insert this notification in your app’s notification history view
                                // ...
                            default:
                                // Unexpected
                        }
                    } else {
                        // ...
                    }
                }
            }
        }
    });
}
});

既存の 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 void dismissNotification(int position) {
    final UserNotification notification = mNewNotifications.get(position);
          
    notification.setUserActionState(UserNotificationUserActionState.DISMISSED);
    notification.saveAsync();
}