ユーザー アクティビティは、アプリケーション内のユーザーのタスクを表すデータコンストラクトです。 後で続行するタスクのスナップショットを保存できます。 Windows タイムライン機能は、テキストとグラフィックスを含むカードとして表される、最近のすべてのアクティビティのスクロール可能なリストを Windows ユーザーに表示します。 ユーザー アクティビティ全般の詳細については、「 デバイス間でもユーザー アクティビティを続行する」を参照してください。 アクティビティを作成または更新するタイミングに関する推奨事項については、 ユーザー アクティビティのベスト プラクティス ガイドを参照してください。
Project Rome SDK を使用すると、Android アプリは、タイムラインなどの Windows 機能で使用するユーザー アクティビティを公開できるだけでなく、エンドポイントとして機能し、タイムラインが Windows デバイス上で行うのと同じようにアクティビティをユーザーに読み取ることもできます。 これにより、クロスデバイス アプリはプラットフォームを超越し、デバイスではなくユーザーに従うエクスペリエンスを提供できます。
これらのシナリオに関連するリファレンス ドキュメントへのリンクについては、 API リファレンス ページを参照してください。
次の手順では、 Project Rome Android サンプル アプリのコードを参照します。
すべての接続デバイス機能には、サポートされているアーキテクチャ (armeabi-v7a、arm64-v8a、x86、またはx86_64) またはエミュレーターのいずれかを備えた Android アプリ開発 IDE と Android デバイスが必要です。 システムは Android 4.4.2 以降を実行している必要があります。
Connected Devices Platform と Notifications の事前セットアップ
リモート接続を実装する前に、Android アプリにリモート デバイスに接続したり、通知を送受信したりするための機能を提供するために必要な手順がいくつかあります。
アプリを登録する
Project Rome SDK のほぼすべての機能 (近くの共有 API の例外) には、Microsoft アカウント (MSA) または Azure Active Directory (AAD) 認証が必要です。 MSA をまだお持ちでなく、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検出を使用する場合にのみ必要であることに注意してください。接続デバイス プラットフォームの他の機能には必要ありません。 さらに、 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;
認証とアカウント管理を設定する
接続デバイス プラットフォームでは、登録プロセスで有効な 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 でのアプリの登録で次のアクセス許可を指定する必要があります (Azure Active Directory > アプリの登録 portal.azure.com >)。
- Microsoft アクティビティ フィード サービス
- このアプリのユーザー通知を配信および変更する
- ユーザーのアクティビティ フィードへのアプリのアクティビティの読み取りと書き込み
- Windows 通知サービス
- デバイスを Windows Notification Service に接続する
- Microsoft Device Directory Service
- デバイスの一覧を表示する
- デバイスとアプリの一覧に追加する
- Microsoft Command Service
- ユーザーのデバイスとの通信
- ユーザー デバイスの読み取り
アプリケーションをプッシュ通知に登録する
Firebase Cloud Messaging サポート用にアプリケーションを Google に登録します。 受信した送信者 ID とサーバー キーを必ず書き留めます。後で必要になります。
登録したら、プッシュ通知機能をアプリの接続済みデバイス プラットフォームに関連付ける必要があります。
mNotificationRegistration = new ConnectedDevicesNotificationRegistration();
mNotificationRegistration.setType(ConnectedDevicesNotificationType.FCM);
mNotificationRegistration.setToken(token);
mNotificationRegistration.setAppId(Secrets.FCM_SENDER_ID);
mNotificationRegistration.setAppDisplayName("SampleApp");
クロスデバイス エクスペリエンスのために Microsoft Windows デベロッパー センターにアプリを登録する
Von Bedeutung
この手順は、Project Rome 機能を使用して Windows 以外のデバイスからデータにアクセスしたり、要求したりする場合にのみ必要です。 Windows デバイスのみを対象とする場合は、この手順を完了する必要はありません。
デベロッパー センター ダッシュボードに移動し、左側のナビゲーション ウィンドウから [クロスデバイス エクスペリエンス] に移動し、次のように新しいクロスデバイス アプリの構成を選択します。
デベロッパー センターのオンボーディング プロセスには、次の手順が必要です。
サポートされているプラットフォームを選択します。アプリがプレゼンスを持ち、クロスデバイス エクスペリエンスが有効になるプラットフォームを選択します。 Graph 通知の統合の場合は、Windows、Android、iOS から選択できます。
アプリ ID を提供する - アプリが存在するプラットフォームごとにアプリ ID を提供します。 Android アプリの場合、これはプロジェクトの作成時にアプリに割り当てたパッケージ名です。 パッケージ名は、Firebase コンソールの [プロジェクトの概要] -> [全般] にあります。 プラットフォームごとに異なる ID (最大 10 個) を追加できます。これは、同じユーザーを対象とするアプリ サーバーから送信された同じ通知を受信できるように、同じアプリの複数のバージョンまたは異なるアプリがある場合です。
MSA または AAD アプリの登録からアプリ ID を指定または選択します。 MSA または AAD アプリの登録に対応するこれらのクライアント ID は、上記の MSA/AAD アプリ登録手順で取得しました。
Graph 通知およびその他の接続デバイス プラットフォーム機能は、主要なプラットフォーム上の各ネイティブ通知プラットフォームを利用して、アプリ クライアント エンドポイント (つまり、WNS (Windows UWP)、FCM (Android の場合)、APNS (iOS の場合) に通知を送信します。 ユーザーを対象とする通知を発行するときに、Graph 通知がアプリ サーバーの通知を配信できるように、これらの通知プラットフォームの資格情報を指定します。 Android の場合、 クラウド メッセージング サービスを有効に することが、Microsoft Graph 通知を使用するための前提条件です。 また、必要な送信者 ID は Firebase Cloud Messaging Sender ID に対応し、API キーはレガシ サーバー キーに対応することに注意してください。 どちらも、スクリーンショットに示すように、Firebase コンソール -> Project -> 設定の [クラウド メッセージング] タブにあります。
最後の手順では、クロスデバイス アプリ ドメインを検証します。これは、登録したアプリのクロスデバイス アプリ ID のように機能するこのドメインの所有権をアプリが持っていることを証明する検証プロセスとして機能します。
プラットフォームの使用
プラットフォームを作成する
開始するには、プラットフォームをインスタンス化するだけです。
ConnectedDevicesPlatform sPlatform = new ConnectedDevicesPlatform(context);
ConnectedDevicesAccountManager イベントをサブスクライブしてユーザー アカウントを処理する
プラットフォームでは、認証されたユーザーがプラットフォームにアクセスする必要があります。 有効なアカウントが使用されていることを確認するには 、ConnectedDevicesAccountManager イベントをサブスクライブする必要があります。
ConnectedDevicesPlatform sPlatform.getAccountManager().accessTokenRequested().subscribe((accountManager, args) -> {
// Get access token
}
ConnectedDevicesPlatform sPlatform.getAccountManager().accessTokenInvalidated().subscribe((accountManager, args) -> {
// Refresh and renew existing access token
}
ConnectedDevicesNotificationRegistrationManager イベントをサブスクライブする
同様に、プラットフォームでは通知を使用してデバイス間でコマンドを配信します。 そのため、 ConnectedDevicesNotificationRegistrationManager イベントをサブスクライブして、クラウド登録状態が使用されているアカウントに対して有効であることを確認する必要があります。 ConnectedDevicesNotificationRegistrationState を使用して状態を確認する
ConnectedDevicesPlatform sPlatform.getNotificationRegistrationManager().notificationRegistrationStateChanged().subscribe((notificationRegistrationManager, args) -> {
// Check state using ConnectedDevicesNotificationRegistrationState enum
}
プラットフォームを起動する
プラットフォームが初期化され、イベント ハンドラーが配置されたので、リモート システム デバイスの検出を開始する準備ができました。
ConnectedDevicesPlatform sPlatform.start();
アプリに既知のユーザー アカウントを取得する
アプリに認識されているユーザー アカウントの一覧が ConnectedDevicesAccountManager と正しく同期されていることを確認することが重要です。
ConnectedDevicesAccountManager.addAccountAsync を使用して、新しいユーザー アカウントを追加します。
public synchronized AsyncOperation<ConnectedDevicesAddAccountResult> addAccountToAccountManagerAsync(ConnectedDevicesAccount account) {
return ConnectedDevicesPlatform sPlatform.getAccountManager().addAccountAsync(account);
}
無効なアカウントを削除するには、ConnectedDevicesAccountManager.removeAccountAsync を使用できます。
public synchronized AsyncOperation<ConnectedDevicesAddAccountResult> removeAccountToAccountManagerAsync(ConnectedDevicesAccount account) {
return ConnectedDevicesPlatform sPlatform.getAccountManager().removeAccountAsync(account);
}
ユーザー アクティビティ チャンネルを初期化する
アプリにユーザー アクティビティ機能を実装するには、まず UserActivityChannel を作成してユーザー アクティビティ フィードを初期化する必要があります。 これは、上記のプラットフォーム初期化手順と同様に扱う必要があります。アプリがフォアグラウンドに来るたびに (ただし、プラットフォームの初期化前には) チェックを行い、場合によってはやり直す必要があります。
また、Microsoft 開発者ダッシュボードの登録を通じて取得されたクロスプラットフォーム アプリ ID も必要です。 次のメソッドは、UserActivityChannel を初期化します。
private UserActivityChannel mActivityChannel;
private UserDataFeed mUserDataFeed;
// ...
/**
* Initializes the UserActivityFeed.
*/
public void initializeUserActivityFeed() {
// define what scope of data this app needs
SyncScope[] scopes = { UserActivityChannel.getSyncScope(), 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
mActivityChannel = getUserActivityChannel();
}
// 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 UserActivityChannel getUserActivityChannel() {
UserActivityChannel channel = null;
try {
// create a UserActivityChannel for the signed in account
channel = new UserActivityChannel(mUserDataFeed);
} catch (Exception e) {
e.printStackTrace();
// handle exception
}
return channel;
}
この時点で、mActivityChannelにUserActivityChannelの参照が存在するはずです。
ユーザーアクティビティを作成して公開する
次に、新しい UserActivity の ID、DisplayText、ActivationURI データを設定します。 ID は一意の文字列である必要があります。 DisplayText は、アクティビティを表示すると (Windows タイムラインなど)、他のデバイスに表示されるため、アクティビティの簡潔な説明にする必要があります。 ActivationUri は、 UserActivity がアクティブになったとき (タイムラインで選択されている場合など) に実行されるアクションを決定します。 次のコードは、これらのフィールドのサンプル データを入力します。
private UserActivity mActivity;
private String mActivityId;
private String mDisplayText;
private String mActivationUri;
// ...
mActivityId = UUID.randomUUID().toString();
mDisplayText = "Created by OneSDK Sample App";
mActivationUri = "http://contoso.com");
次に、新しい UserActivity インスタンスを作成するメソッドを指定します。
// Create the UserActivity (with unique ID) using a custom method.
mActivity = createUserActivity(mActivityChannel, mActivityId);
// ...
// Custom method for creating a new UserActivity
@Nullable
private UserActivity createUserActivity(UserActivityChannel channel, String activityId)
{
UserActivity activity = null;
AsyncOperation<UserActivity> activityOperation = channel.getOrCreateUserActivityAsync(activityId);
try {
activity = activityOperation.get();
Log.d("UserActivityFragment","Created user activity successfully");
} catch (Exception e) {
e.printStackTrace();
Log.d("UserActivityFragment","Created user activity successfully");
}
return activity;
}
UserActivity インスタンスを取得したら、上記で定義したデータを設定します。
//set the properties of the UserActivity:
// Display Text will be shown when the UserActivity is viewed on other devices
mActivity.getVisualElements().setDisplayText(mDisplayText);
// ActivationURI will determine what is launched when your UserActivity is activated from other devices
mActivity.setActivationUri(mActivationUri);
最後に、アクティビティをクラウドに発行します。
// This code saves and publishes the activity
AsyncOperation<Void> operation = mActivity.saveAsync();
operation.whenCompleteAsync(new AsyncOperation.ResultBiConsumer<Void, Throwable>() {
@Override
public void accept(Void aVoid, Throwable throwable) throws Throwable {
if (throwable != null)
{
Log.d("UserActivityFragment", "Failed to save");
} else {
Log.d("UserActivityFragment", "User activity saved");
}
}
});
ヒント
上記のプロパティに加えて、構成できる他の多くの機能があります。 UserActivity をカスタマイズするさまざまな方法の詳細については、UserActivity、UserActivityVisualElements、および UserActivityAttribution クラスを参照してください。 ユーザー アクティビティの設計方法に関する詳細な推奨事項については、 ユーザー アクティビティのベスト プラクティス ガイドを参照してください。
既存のユーザー アクティビティを更新する
既存のアクティビティがあり、その情報を更新する場合 (新しいエンゲージメントや変更されたページなどが発生した場合)、 UserActivitySession を使用して更新できます。
private UserActivitySession mActivitySession;
// ...
if (mActivity != null)
{
// create a session from a previous UserActivity instance.
mActivitySession = mActivity.createSession();
Log.d("UserActivityFragment", "Starting");
}
セッションを作成すると、アプリは UserActivity のプロパティに必要な変更を加えることができます。 変更が完了したら、セッションを閉じます。
mActivitySession.close();
mActivitySession = null;
Log.d("UserActivityFragment", "Stopping");
UserActivitySession は、UserActivitySessionHistoryItem を作成する方法と考えることができます (次のセクションで説明します)。 ユーザーが新しいページに移動するたびに新しい UserActivity を作成するのではなく、ページごとに新しいセッションを作成するだけです。 これにより、より直感的で整理されたアクティビティの読み取りエクスペリエンスが実現します。
ユーザー アクティビティの読み取り
アプリでは、Windows タイムライン機能と同様に、ユーザー アクティビティを読み取ってユーザーに表示できます。 ユーザー アクティビティの読み取りを設定するには、前の手順と同じ UserActivityChannel インスタンスを使用します。 このインスタンスは、特定の期間中の特定のアクティビティにおけるユーザーのエンゲージメントを表す UserActivitySessionHistoryItem インスタンスを公開できます。
private ArrayList<UserActivitySessionHistoryItem> mHistoryItems;
// ...
mHistoryItems.clear();
Log.d("UserActivityFragment", "Read");
//Async method to read activities. Last (most recent) 5 activities will be returned
AsyncOperation<UserActivitySessionHistoryItem[]> operation = mActivityChannel.getRecentUserActivitiesAsync(5);
operation.whenCompleteAsync(new AsyncOperation.ResultBiConsumer<UserActivitySessionHistoryItem[], Throwable>() {
@Override
public void accept(UserActivitySessionHistoryItem[] result, Throwable throwable) throws Throwable {
if (throwable != null)
{
Log.d("UserActivityFragment", "Failed to read user activity!" + throwable.getMessage() + " " + throwable.getStackTrace());
} else {
// get the returned UserActivitySessionHistoryItems
for (UserActivitySessionHistoryItem item : result)
{
mHistoryItems.add(item);
}
}
}
});
これで、アプリに UserActivitySessionHistoryItemの一覧が設定されます。 これらのそれぞれで、基になる UserActivity を配信できます (詳細については UserActivitySessionHistoryItem を参照)、ユーザーに表示できます。