共用方式為


How-To指南:與 MS Graph 通知整合 (Windows UWP)

在 Windows 上使用 Graph 通知用戶端 SDK 時,Windows UWP 應用程式可以執行必要的註冊步驟來成為接收端點,以接收應用程式伺服器發佈給某位使用者的通知。 然後,便可使用 SDK 來管理用戶端上的通知,包括接收抵達此用戶端的新通知承載、管理通知的狀態,以及擷取通知歷程記錄。 如需 MS Graph 通知及其如何能夠以人為中心來傳遞通知的詳細資訊,請參閱 Microsoft Graph 通知概觀

請參閱 API 參考頁面,來取得通知案例相關參考文件的連結。

用於存取連線裝置平台以便使用 Graph 通知的預備設定

您必須採取幾個步驟才能與 Graph 通知整合

  • 註冊 MSA 或 AAD 應用程式
  • 開發人員中心上線,以提供跨平台應用程式身分識別和推播通知認證
  • 新增 SDK 並初始化連線裝置平台
  • 讓通知服務與連線裝置平台相關聯

首先,您必須完成 MSA 和/或 AAD 應用程式的註冊。 如果您已完成註冊,請跳至下一節。

MSA 和 AAD 驗證註冊

SDK 的所有功能 (包括通知在內) 都需要 Microsoft 帳戶 (MSA) 或 Azure Active Directory (AAD) 驗證註冊,但鄰近分享 API 除外。

如果您還沒有 MSA 但想要使用,請在 account.microsoft.com 上註冊。

接下來,如果您要使用 MSA 作為使用者的驗證和身分識別架構,則必須遵循應用程式註冊入口網站上的指示 (如果您沒有 Microsoft 開發人員帳戶,則必須先建立一個),向 Microsoft 註冊應用程式。 您應該會收到應用程式的用戶端識別碼字串;請務必記住其所在位置或將其儲存起來。 稍後在 Graph 通知上線時將會用到此字串。 請注意,使用 MSA 驗證的應用程式必須註冊為 Live SDK 應用程式,如下所示。 應用程式註冊入口網站

如果您要撰寫使用 AAD 作為公司帳戶或學校帳戶驗證與身分識別架構的應用程式,則必須透過 Azure Active Directory 驗證程式庫來註冊應用程式,以取得用戶端識別碼,如下所示。 AAD 註冊入口網站 建立新的應用程式註冊時,需要一些許可權才能使用 Graph 通知和其他已連線的裝置平臺功能。 請參閱下面內容。 AAD 註冊入口網站 – 設定 – 必要許可權

  • 新增使用者登入權限,如下所示。 必要許可權 – AAD 使用者設定檔
  • 新增裝置資訊的命令服務權限,如下所示。 必要許可權 – 裝置
  • 在活動摘要服務 API 底下新增 Graph 通知權限,如下所示。 必要許可權 – 裝置
  • 最後,如果您要撰寫跨平台應用程式 (包括在 Windows 上執行的 UWP 應用程式),請務必新增 Windows 通知服務權限,如下所示。 必要許可權 – WNS

接下來,您必須使用 Microsoft Windows 開發人員中心來上線,以便能夠存取連線裝置平台,從而能與跨裝置體驗 (包括使用 Graph 通知) 整合。 如果您已完成註冊,請跳至下一節。

在 Microsoft Windows 開發人員中心註冊應用程式以獲得跨裝置體驗

接下來,您必須註冊應用程式以獲得 Microsoft 開發人員儀表板的跨裝置體驗功能。 這個程序與上述步驟所說明的 MSA 和 AAD 應用程式註冊不同。 這個程序的主要目的是要讓平台特有的應用程式身分識別與連線裝置平台所辨識的跨平台應用程式身分識別相對應,並同時授權 Microsoft Graph 通知使用與每個 OS 平台相對應的原生推播通知服務來傳送通知。 在此情況下,其可讓 Graph 通知透過 WNS (Windows 推播通知服務) 將通知傳送給 Windows UWP 應用程式端點。 請移至開發人員中心儀表板、從左側瀏覽窗格瀏覽至跨裝置體驗,然後選取要設定新的跨裝置應用程式,如下所示。 開發人員中心儀表板 – 跨裝置體驗

開發人員中心的上線程序需要執行下列步驟:

  • 選取支援的平台 – 選取會出現應用程式並為應用程式啟用跨裝置體驗的平台。 在 Graph 通知整合的案例中,您可以選取 Windows、Android 及/或 iOS。 如下所示。 跨裝置體驗 – 支援的平臺

  • 提供應用程式識別碼 – 針對會出現應用程式的每個平台提供應用程式識別碼。 如下所示。 跨裝置體驗 – 應用程式識別碼

注意

您可以為每個平台新增不同的識別碼 (最多十個) – 這是為了讓同一個應用程式的多個版本 (或甚至是不同的應用程式),能夠接收應用程式伺服器傳送給同一位使用者的相同通知。

  • 請提供或選取來自 MSA 和/或 AAD 應用程式註冊的應用程式識別碼。 這些對應至 MSA 或 AAD 應用程式註冊的用戶端識別碼,會從上面先前的 MSA/AAD 應用程式註冊步驟取得。 如下所示。 跨裝置體驗 – MSA 和 AAD 應用程式註冊
  • Graph 通知和其他連線裝置平台功能會利用主要平台上的每個原生通知平台,將通知往下傳送給應用程式用戶端端點,也就是 WNS (適用於 Windows UWP)、GCM (適用於 Android) 和 APNS (適用於 iOS)。 請提供這些通知平台的認證,以便在您發佈目標為使用者的通知時,Graph 通知能夠為應用程式伺服器傳遞通知。 如下所示。 跨裝置體驗 – 推送認證

注意

在 Windows UWP 應用程式中,您必須先啟用 WNS 推播通知才能使用 Microsoft Graph 通知。 如需詳細資訊,請參閱 WNS 概觀。 完成上線後,您便可以透過 Windows 開發人員中心對連線裝置平台提供推播認證。

  • 最後一個步驟是驗證跨裝置應用程式網域,這可作為驗證程序來證明應用程式具有此網域的擁有權,其作用類似已註冊應用程式的跨裝置應用程式身分識別。 如下所示。
    跨裝置體驗 – 網域驗證 現在您已設定上線! 請繼續進行下一節。

接下來,您必須將 Project Rome SDK 新增至專案,並初始化連線裝置平台。 如果您已完成註冊,請跳至下一節。

新增 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的檔案,並貼上ProGuard_Rules_for_Android_Rome_SDK.txt的內容。

在專案的 AndroidManifest.xml 檔案中,於 <manifest> 元素內新增下列權限 (如果其中還沒有這些權限)。 這可讓應用程式獲得權限而能夠連線至網際網路,並在裝置上啟用藍牙探索。

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

注意

只有在使用藍牙探索時才需要藍牙相關權限;連線裝置平台中的其他功能則不需要這些權限。 此外,只有在 Android SDK 21 及更新版本上才需要 ACCESS_COARSE_LOCATION。 在 Android SDK 23 及更新版本上,開發人員還必須提示使用者授與在執行階段存取位置。

接下來,移至您想要在其中新增連線裝置功能的活動類別。 匯入 connecteddevices 命名空間。

import com.microsoft.connecteddevices.*;

根據您所實作的案例,您可能不需要所有命名空間。 您可能還需要在過程中新增其他 Android 原生命名空。

初始化連線裝置平台

必須先在應用程式內初始化此平台,才能使用連線裝置的功能。 初始化步驟應該會發生在主要類別的 onCreateonResume 方法中,因為必須先進行過初始化步驟才能再進行其他連線裝置案例。

您必須具現化 Platform 類別。 Platform 建構函式會採用三個參數:Context (用於應用程式)、NotificationProviderUserAccountProvider

在某些情況下才需要 NotificationProvider 參數。 在使用 Microsoft Graph 通知時就必須有此參數。 請先讓此參數保持 null,並於下一節了解如何讓用戶端 SDK 能夠透過原生推播通道來處理以使用者為中心的傳入通知。

需要有 UserAccountProvider 才能傳遞 OAuth 2.0 存取權杖而讓目前的使用者能夠存取連線裝置平台。 系統會在應用程式首次執行時,以及在平台管理的重新整理權杖到期時呼叫此參數。

為了協助開發人員更輕鬆地使用平台來上線,我們已提供適用於 Android 和 iOS 的帳戶提供者實作。 這些實作可於驗證提供者範例中找到,您可以使用這些實做來為應用程式取得 OAuth 2.0 存取權杖和重新整理權杖。

設定驗證和帳戶管理

連線裝置平台需要有效的 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"

注意

裝置轉送 API 則不支援 Azure Active Directory (AAD) 帳戶。

無論您是否使用提供的ConnectedDevicesAccountManager實作,如果您使用 AAD,則必須在 azure Active Directory > Azure 入口網站 (portal.azure.com 應用程式註冊) > 上的應用程式註冊中指定下列許可權:

  • Microsoft 活動摘要服務
    • 傳遞並修改此應用程式的使用者通知
    • 在使用者的活動摘要中讀取及寫入應用程式活動
  • Windows 通知服務
    • 將裝置連線到 Windows 通知服務
  • Microsoft 裝置目錄服務
    • 查看裝置清單
    • 務必新增至裝置和應用程式的清單
  • Microsoft 命令服務
    • 與使用者裝置通訊
    • 讀取使用者裝置

在下面的程式碼中,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 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;
}

mSignInHelper 初始化所在的主要類別中,新增下列程式碼。

private Platform mPlatform;

//...

mPlatform = PlatformHelperClass.getOrCreatePlatform(this, mSignInHelper, null);

當應用程式離開前景時,請關閉該平台。

mPlatform.shutdownAsync();

最後,您必須讓應用程式能夠接收推播通知。 如果您已完成註冊,請跳至下一節。

讓連線裝置平台與每個行動裝置平台的原生推播通知相關聯。

如先前所述,應用程式用戶端必須在註冊過程中,提供要讓每個行動裝置平台針對用戶端 SDK 和連線裝置平台來使用的原生推播通知管線相關知識,以便讓 Graph 通知服務在應用程式伺服器透過 Microsoft Graph API 發佈以使用者為目標的通知時,將通知發散給每個應用程式用戶端端點。

在上述步驟中,您已使用 null notificationProvider 參數來初始化平台。 在此,您必須建構和傳遞會實作 NotificationProvider 的物件。 要注意的重點是 getNotificationRegistrationAsync 方法,其必須傳回 NotificationRegistration 執行個體。 NotificationRegistration 會負責向連線裝置平台提供該通知服務的存取權杖 (和相關資訊)。

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 時傳遞此註冊。 然後,平台的初始化呼叫應該就會向本機平台提供推播通知服務的存取權,從而讓應用程式能夠接收來自 Microsoft Graph 通知伺服器端的資料。

將傳入的推播通知傳遞給用戶端 SDK

現在,請使用 onMessageReceived 方法 (通知處理方法) 的特殊多載來擴充原生接聽程式服務類別 (在此例為 FirebaseMessagingService,因為本教學課程使用 Firebase 雲端通訊)。

由於合規性、安全性和可能的最佳化,來自 Graph 通知伺服器端的傳入 Google 雲端通訊通知可能會是拍肩提醒,而不會包含應用程式伺服器一開始所發佈的任何資料。 在擷取應用程式伺服器所發佈的實際通知內容時,會在用戶端 SDK API 後面隱匿進行。 因此,SDK 可以提供一致的程式設計模式,在此模式中,應用程式用戶端一律會將傳入的 Google 雲端通訊承載傳遞至 SDK。 這可讓 SDK 判斷這是否為連線裝置平台案例的通知 (在寫 Android 的原生 Google 雲端通訊通道用於其他用途時由應用程式用戶端),以及此傳入通知對應到哪個案例/功能 (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");
    }
}

應用程式現在可以處理來自連線裝置平台的通知。

初始化 Graph 通知通道

綜觀來看,SDK 可讓應用程式訂閱不同通道,以便接收及管理各種類型的使用者資料,包括 Graph 通知、使用者活動等等。 這些資料全都會儲存在 UserDataFeed 內並進行同步處理。 UserNotification 是透過 Graph 通知所傳送、與鎖定使用者的通知相對應的類別和資料類型。 若要與 Graph 通知整合並開始接收應用程式伺服器所發佈的 UserNotification,您必須先藉由建立 UserNotificationChannel 來初始化使用者資料摘要。 此程序的處理方式應該和上面的平台初始化步驟一樣:應該進行檢查,並可能要在每次應用程式移到前景時 (但不要在平台初始化之前) 重做。

建立 UserNotificationReader 來接收傳入的 UserNotification 並存取 UserNotification 歷程記錄

擁有 UserNotificationChannel 參考後,您需要有 UserNotificationReader 才能讓 SDK 從伺服器擷取實際的通知內容。 在此情況下,UserNotificationReader 可讓應用程式用戶端存取此資料摘要,而能夠透過事件接聽程式接收最新的通知承載,或能夠存取可作為使用者通知歷程記錄檢視模型的完整 UserNotification 集合。

下列程式碼會示範相關步驟,以便讓您知道如何具現化使用者通知通道、建立使用者通知讀取器,以及在使用者通知讀取器上新增事件處理常式,從而在連線裝置平台完成每個同步處理作業,且有新的變更需要讓您知道時加以觸發。


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 會在其電腦及其安裝應用程式用戶端的手機上收到此通知。 使用者在電腦上按一下通知,並進入應用程式來處理對應的工作。 此電腦上的應用程式用戶端隨即會呼叫連線裝置平台 SDK 來更新對應 UserNotification 的狀態,以便讓此更新同步處理到這位使用者的所有裝置。 其他應用程式用戶端則會在收到此狀態更新時,即時地從裝置的通知中心/通知匣/控制中心移除對應的視覺警示/訊息/快顯通知。 這便是通知在使用者的所有裝置上全面關閉的方式。

提示

UserNotification 類別目前提供 2 種狀態更新,您可以修改 UserNotificationReadState 或 UserNotificationUserActionState 並定義您自己的邏輯來指出通知有所更新時應該如何處理。 例如,您可以將 UserActionState 標示為已啟用或已關閉,並根據該值來實作通用關閉。 或者,您也可以同時將 ReadState 標示為已讀取或未讀取,並據此決定應該在應用程式內的通知歷程記錄檢視中顯示哪些通知。 下列程式碼片段會示範如何將通知的 UserNotificationUserActionState 標示為已關閉。

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();
    }
}