原文鏈接:https://github.com/chenxizhang/office365dev/blob/e9b5a59cb827841d36692cc4ec52c11d43062e04/docs/timeline.md
前言
前不久微軟正式放出了Windows 10 春季更新(1803),其中有一個非常有特色的應用,就是Windows 10 新增了一個Timeline(時間線)的應用,這個應用可以讓用戶一目了然地看到最近一段時間所有在Windows中的活動,包括瀏覽過什么網頁,打開過什么文檔,設置過什么選項等。下圖是一個示范的效果圖:
請注意,這里看到的信息不是一個靜態的圖片,每一個卡片都是可以點擊的,而且點擊之后會通過調用對應的應用程序自動打開這些活動(恢復到之前的狀態),就好像時光倒流了一樣。
看起來很酷,不是嗎?那么,這樣一個應用到底是怎么實現的呢?我們如果也想實現類似的場景,有什么樣的思路呢?答案在上周的Microsoft Build 大會上做了揭曉:其實Timeline是一個基於Microsoft Graph實現的應用,只不過他讀取的數據,不僅限於Office 365的文檔歷史,還包括了Windows 10 上面的活動,這也是近年來一個重大的變化:微軟已經把Office 365、Windows 10、EMS這三個產品合並為一個——Microsoft 365,將為最終用戶提供最佳的體驗,他們的能力也將統一通過Microsoft Graph向開發者提供服務。
原理解析
首先,從技術上說,要實現這個Timeline應用,用戶需要允許相關的活動源將有關信息發送給Microsoft Graph。這里所謂的活動源,可以是Office客戶端,也可以是Windows 10的應用程序。微軟一直致力於保護用戶的隱私,所以這個Timeline的功能,默認是不開啟的,只有用戶在被明確告知上述行為並且選擇接受的情況下,才會開始收集數據並進行展現。
其次,除了Windows 10自帶的Timeline應用,其實只要幾行代碼,就能實現一個類似的時間線應用。那么問題就來了,這些應用之間的數據是不是隔離的呢?答案是肯定的,也就是說Windows 10這個Timeline應用只能讀取到它在經用戶同意的前提下收集的那部分活動數據,而我們自定義的應用也是如此。
最后,這里面還有一個有意思的概念。一個活動(Activity)可以對應一個或者多個歷史記錄(History Items)。歷史紀錄相當於是活動在某個時間點的快照。
據說這個技術,最早在內部有一個代碼叫做“Project Rome”,現在合並到了Microsoft Graph中,並且已經在V1.0中提供。相關官方文檔請參考 https://developer.microsoft.com/en-us/graph/docs/concepts/activity-feed-concept-overview .
創建Timeline應用
有了如上概念,我們就閑話少說,擼起袖子加油干吧。因為要訪問Microsoft Graph,所以你就必須要注冊一個AAD的應用程序。注冊這樣一個應用程序沒有什么特別的,唯一要了解的是,要支持用戶活動的讀寫,需要申請一個UserActivity.ReadWrite.CreatedByApp的委派權限(Delegated Permission),如下圖所示
大家可以看到,這個權限並不需要管理員認可就能工作。
請注意,目前UserActivity.ReadWrite.CreatedByApp這個權限,僅在國際版的環境中可以用,而且必須在AAD 1.0的環境中實現。AAD 2.0還不支持,國內版(Gallatin)也暫時不支持。
如何發布Activity
Windows 10自帶的Timeline其實是一個UWP應用,不過你可以用你最熟悉的方式來實現自定義的Timeline應用。但拋開這些具體的界面,我們可以快速了解一下如何創建和更新用戶活動(Activity)。
創建或更新Activity的API,請參考 https://developer.microsoft.com/en-us/graph/docs/api-reference/v1.0/api/projectrome_put_activity, 大體上說,這里的關鍵是用PUT方法操作,同時我們既可以單獨創建Activity,也可以在創建Activity的時候同時創建History Item,后者也稱為“Deep Insert”。
為了給大家直觀演示效果,我這里簡化一下步驟。我將采用官方的Microsoft Graph Explorer來模擬一個客戶端,並且直接用REST API來進行操作。如果你對Microsoft Graph Explorer不太熟悉,你可能需要先閱讀一下這篇文章。
正如上一節提到的,你需要確保授予了UserActivity.ReadWrite.CreatedByApp這個權限,請參考下圖
我直接用官方給的例子,為當前用戶新增一個網絡文章瀏覽的活動,請注意下面的appActivityId、activitySourceHost、activationUrl、visualElements 是必須的。這個例子的意思是指定義了用戶這個活動是瀏覽了 http://www.contoso.com/article?id=12345 這個Url所指向的一篇文章。
{
"appActivityId": "/article?12345",
"activitySourceHost": "https://www.contoso.com",
"userTimezone": "Africa/Casablanca",
"appDisplayName": "Contoso, Ltd.",
"activationUrl": "http://www.contoso.com/article?id=12345",
"contentUrl": "http://www.contoso.com/article?id=12345",
"fallbackUrl": "http://www.contoso.com/article?id=12345",
"contentInfo": {
"@context": "http://schema.org",
"@type": "Article",
"author": "Jennifer Booth",
"name": "How to Tie a Reef Knot"
},
"visualElements": {
"attribution": {
"iconUrl": "http://www.contoso.com/icon",
"alternateText": "Contoso, Ltd.",
"addImageQuery": "false",
},
"description": "How to Tie a Reef Knot. A step-by-step visual guide to the art of nautical knot-tying.",
"backgroundColor": "#ff0000",
"displayText": "Contoso How-To: How to Tie a Reef Knot",
"content": {
"$schema": "http://adaptivecards.io/schemas/adaptive-card.json",
"type": "AdaptiveCard",
"body":
[{
"type": "TextBlock",
"text": "Contoso MainPage"
}]
}
}
}
在Microsoft Graph Explorer 中用PUT方法,將上述數據,發送到https://graph.microsoft.com/v1.0/me/activities/%2Farticle%3F12345, 同時記得設置Content-Type為application/json
如果一切正常的話,你將收到一個回復,里面包含了在Microsoft Graph中創建的Activity的信息,這里會返回全局唯一的id屬性。
請注意,如果要更新,也是使用同樣的一個命令。而如果要進行刪除,則需要用 DELETE 方法,請參考 https://developer.microsoft.com/en-us/graph/docs/api-reference/v1.0/api/projectrome_delete_activity。
如何查詢Activity
有兩個接口用來查詢用戶活動(Activity),分別是
- 獲取用戶活動(可以獲取全部,也可以獲取指定篩選條件的活動),如果需要同時包含歷史信息,則需要添加查詢參數 $expand=historyitems。 詳細的API說明,請參考 https://developer.microsoft.com/en-us/graph/docs/api-reference/v1.0/api/projectrome_get_activities 。
- 獲取用戶最近的活動。可以理解為上一種的簡化版本,Microsoft Graph會查詢最近的一個History Items,然后找到它們對應的活動條目。詳細的API說明,請參考 https://developer.microsoft.com/en-us/graph/docs/api-reference/v1.0/api/projectrome_get_recent_activities。
下面是一個簡單的查詢例子
結語
這一篇文章帶領大家了解了Windows 10最新版本中Timeline這個功能的實現原理,並且用實例演示了如何使用Microsoft Graph來實現自定義的類似應用,我用Microsoft Graph Explorer做了演示,大家可以一目了然地看到接口的調用和返回值。
因為這個功能比較新,Microsoft Graph的SDK中,還沒有完全包含這個功能,我還發現.NET SDK中存在一點小問題,已經跟產品團隊反饋了。所以,如果你現在開始做實踐,建議還使用REST API的方式。






