UWP - 搭配 Azure AD Application 取得 App 分析資料

Dev Center 提供了 REST 的方式讓開發人員不需要登入 Dev Center 就可以拿到 App 的相關分析資料,例如:in-app purchase acquisitions, ratings and reviews, as well as app health,進一步使用習慣的分析工具進行分析。因此,該篇針對 <Windows Store analytics API now available> 筆記如何使用。

[事前準備]

接下來根據<Windows Store analytics API now available> 中的説明介紹使用步驟。

[運作步驟]

1. 先建立或是取得既有的 Azure AD Application
    利用<UWP - Manage user in the Windows Dev Center>介紹所建立一個 managed role 的賬號登入 Dev Center。
    切換到 Dashboard -> Account settings -> Manage users 建立一個 Azure AD Application
   
     上述的圖裏面幾個欄位在填寫的地方要注意:

  • Name:可自訂需要的名字
  • Reply URL:使用者可以從此 URL 登入並使用您的 Azure AD 應用程式 (也稱為應用程式 URL 或登入 URL)。
    長度不能超過 256 個字元。值在: Azure Management Portal -> Active Directory -> directory -> application -> Configure 中的 Single Sign-on section。
    如下圖:
  • App ID URI:格式:https://YOURTENANTNAME.onmicrosoft.com/YOURAPPNAME
    YOURTENANTNAME:在 Azure AD 中的 tenant name,如下圖:

    這個值來自跟 Reply URL 的路徑,需要先到 Azure Management Portal 進入使用的 AD,瀏覽器就可以看到同上面的 URL 。
    YOURAPPNAME:輸入預計要抓到的 App Name
  • Roles:請選擇 Manager。

 

2. 利用 tenant Id + Client ID + Key 來取得 Azure 與 Dev Center 的驗證

  • 建立好 Azure Application 之後,點擊 Add Key 取得 analysis key:

  • 利用 Azure portal 的 Active Directionary 拿到的 tenent id:
    tenent id 就藏在 Active Directionary 網頁的 URL 裏面,格式如下:
    https://manage.windowsazure.com/@<your_tenant_name>#Workspaces/ActiveDirectoryExtension/Directory/<your_tenant_ID>/directoryQuickStart

    爲什麽需要這個呢?因爲使用 Analysis API 需要先經過 OAth2 的驗證,所以需要 tenant Id 組合完整的驗證 URL:https://login.microsoftonline.com/<tenant id>/oauth2/token.
  • 宣告要使用的 resource scope:https://manage.devcenter.microsoft.com (目前固定)

參考<Access analytics data using Windows Store services>,利用上面三個關鍵參數來取得 access token:

string tenantId = "";
string clientId = "";
string clientSecret = "";

string scope = "https://manage.devcenter.microsoft.com";

private string GetDevCenterAccessToken()
{
    string tokenEndpoint = string.Format("https://login.microsoftonline.com/{0}/oauth2/token", tenantId);
    using (WebClient client = new WebClient())
    {
         string param = string.Format("grant_type=client_credentials&client_id={0}&client_secret={1}&resource={2}", clientId, clientSecret, scope);
         //application/x-www-form-urlencoded
         string json = client.UploadString(tokenEndpoint, param);
         AccessTokenObject result = JsonConvert.DeserializeObject<AccessTokenObject>(json);
         return result.AccessToken;
     }
}

public class AccessTokenObject
{
    [JsonProperty("token_type")]
    public string token_type { get; set; }

    [JsonProperty("expires_in")]
    public string ExpliresIn { get; set; }

    [JsonProperty("expires_on")]
    public string ExpiresOn { get; set; }

    [JsonProperty("not_before")]
    public string NotBefore { get; set; }

    [JsonProperty("resource")]
    public string Resource { get; set; }

    [JsonProperty("access_token")]
    public string AccessToken { get; set; }
}

取得 access token 的 json:

{"token_type":"Bearer",
 "expires_in":"3600",
 "expires_on":"1461601823",
 "not_before":"1461597923",
 "resource":"https://manage.devcenter.microsoft.com",
 "access_token":"_zjbYw0A5n5qXGEoqPBp6nan6FTcrUzhIkIhQeDHnmg"
}

如果請求發生失敗的話會收到 status code = 400 的錯誤,請先確定給的 post data 是否正確。

 

3. 操作 API 範例説明

使用 API 的時候要記得把 access token 放到 HTTP Header 裏面:

Heder Type Description
Authorization string Required. The Azure AD access token in the form Bearer <token>.

API 的 URL 爲:https://manage.devcenter.microsoft.com/v1.0/my/analytics/failurehits

參數裏面最重要的是:applicationId,該值就是 App 的 Id (例如:https://www.microsoft.com/store/apps/9nblggh5f25p ,後面的 9nblggh5f25p)。

要特別注意 filter 參數有複雜的定義:

Filter fields

The filter parameter of the request body contains one or more statements that filter the rows in the response. Each statement contains a field and value that are associated with the eq or ne operators, and statements can be combined using and or or. Here are some example filter parameters:
•filter=market eq 'US' and gender eq 'm'
•filter=(market ne 'US') and (gender ne 'Unknown') and (gender ne 'm') and (market ne 'NO') and (ageGroup ne 'greater than 55' or ageGroup ne ‘less than 13’)

更多參數的説明可以參考<Get error reporting data>。

private void GetErrorReport(string accessToken)
{
	string url = "https://manage.devcenter.microsoft.com/v1.0/my/analytics/failurehits";
	string queryStr = "applicationId=" + "9nblggh5f25p" +
					  "&startDate=" + "2016/04/01" +
					  "&endDate=" + "2016/04/30" +
					  "&top=10&skip=0";
	using (WebClient client = new WebClient())
	{
		string link = string.Format("{0}?{1}", url, queryStr);
		client.Headers.Add("Authorization", string.Format("Bearer {0}", accessToken));
		string json = client.DownloadString(link);
	}
}

得到的 json 内容:

{
  "Value": [
    {
      "date": "2016-04-09",
      "applicationId": "9NBLGGH5F25P",
      "applicationName": "TWBUSUWP",
      "failureName": "STOWED_EXCEPTION_MISSING_CLR_METADATA_802b000a_14035PouMason.TWBUSUWP!unknown_error_in_application",
      "failureHash": "bf7fcb19-c663-8c40-3a39-f0f08c34e47b",
      "symbol": "14035PouMason.TWBUSUWP!unknown_error_in_application",
      "osVersion": "Windows 10",
      "eventType": "crash",
      "market": "US",
      "deviceType": "mobile",
      "packageName": "14035poumason.twbusuwp_1.1.0.0_x86__2mew08e2h8n4p",
      "packageVersion": "1.1.0.0",
      "deviceCount": 1.0,
      "eventCount": 1.0
    }
  ],
  "@nextLink": "failurehits?applicationId=9nblggh5f25p&aggregationLevel=day&startDate=2016/01/01&endDate=2016/04/25&top=2&skip=2",
  "TotalCount": 1
}

上面的 @nextLink 如果有值代表後面還有資料(值爲一個 URL ),要記得做 load more (或下一頁) 的效果。

 

API 的 URL:https://manage.devcenter.microsoft.com/v1.0/my/analytics/ratings

最重要的參數:applicationId,可以搭配 filter, aggregationLevel (day, week, or month), orderby 調整要顯示的内容。

private void GetRateReport(string accessToken)
{
	string url = "https://manage.devcenter.microsoft.com/v1.0/my/analytics/ratings";
	string queryStr = "applicationId=" + "9nblggh5f25p" +
					  "&startDate=" + "2016/01/01" +
					  "&endDate=" + "2016/04/30" +
					  "&top=2&skip=0" +
					  "&aggregationLevel=" + "month";
	using (WebClient client = new WebClient())
	{
		string link = string.Format("{0}?{1}", url, queryStr);
		client.Headers.Add("Authorization", string.Format("Bearer {0}", accessToken));
		string json = client.DownloadString(link);
	}
}

得到的 json 内容:

{
  "Value": [
    {
      "date": "2016-02-01",
      "applicationId": "9NBLGGH5F25P",
      "applicationName": "TWBUSUWP",
      "market": "TW",
      "osVersion": "10.0.10586.107",
      "deviceType": "Phone",
      "isRevised": false,
      "oneStar": 0,
      "twoStars": 1,
      "threeStars": 0,
      "fourStars": 0,
      "fiveStars": 0
    },
    {
      "date": "2016-02-01",
      "applicationId": "9NBLGGH5F25P",
      "applicationName": "TWBUSUWP",
      "market": "TW",
      "osVersion": "10.0.10586.71",
      "deviceType": "PC",
      "isRevised": false,
      "oneStar": 0,
      "twoStars": 0,
      "threeStars": 0,
      "fourStars": 0,
      "fiveStars": 1
    }
  ],
  "@nextLink": "ratings?applicationId=9nblggh5f25p&aggregationLevel=month&startDate=2016/01/01&endDate=2016/04/25&top=2&skip=2",
  "TotalCount": 9
}

可以發現回來的結果裏面 1~5 顆星竟然是用 oneStart ~ fiveStarts 來定義。

 

API 的 URL:https://manage.devcenter.microsoft.com/v1.0/my/analytics/reviews

最重要的參數:applicationId,可以搭配 filter, orderby 調整要顯示的内容,例如:想要過濾某些關鍵字的 review 内容,可以下 filter=contains(reviewText,'great') and contains(reviewText,'ads')

private void GetReviewReport(string accessToken)
{
	string url = "https://manage.devcenter.microsoft.com/v1.0/my/analytics/reviews";
	string queryStr = "applicationId=" + "9nblggh5f25p" +
					  "&startDate=" + "2016/01/01" +
					  "&endDate=" + "2016/04/30" +
					  "&top=2&skip=0" +
					  "&filter=" + "contains(reviewText,'查詢') and contains(reviewText,'錯誤')";
	using (WebClient client = new WebClient())
	{
		string link = string.Format("{0}?{1}", url, queryStr);
		client.Headers.Add("Authorization", string.Format("Bearer {0}", accessToken));
                // 要記得加上才會有正確的編碼文字
                client.Encoding = Encoding.UTF8;
		string json = client.DownloadString(link);
	}
}

得到的 json 内容:

{
  "Value": [
    {
      "date": "2016-02-05",
      "applicationId": "9NBLGGH5F25P",
      "applicationName": "TWBUSUWP",
      "market": "TW",
      "osVersion": "10.0.10586.71",
      "deviceType": "PC",
      "isRevised": false,
      "packageVersion": "",
      "deviceModel": "Gigabyte Technology Co., Ltd.-Z97X-UD3H",
      "productFamily": "PC",
      "deviceRAM": 16384,
      "deviceScreenResolution": "1920 x 1080",
      "deviceStorageCapacity": 244198,
      "isTouchEnabled": false,
      "reviewerName": "Killy",
      "rating": 5,
      "reviewTitle": "收尋的小建議",
      "reviewText": "當我要回來再收尋時,希望我的收尋停在台南,不要再跳回台北了,不然一直要重找很麻煩。\r\n還有,台南2號公車,有崑山科大往安平,但沒有安平往崑山科大,其它很多也是都只有單向。",
      "helpfulCount": 0,
      "notHelpfulCount": 0,
      "responseDate": null,
      "responseText": ""
    }
  ],
  "@nextLink": "Reviews?applicationId=9nblggh5f25p&startDate=2016/01/01&endDate=2016/04/25&top=2&skip=2",
  "TotalCount": 9
}

 

如果在使用 API 發生錯誤時會收到如下範例的 JSON:

{
    "code":"BadRequest",
    "data":[],
    "details":[],
    "innererror":{
        "code":"InvalidQueryParameters",
        "data":[
            "top parameter cannot be more than 10000"
        ],
        "details":[],
        "message":"One or More Query Parameters has invalid values.",
        "source":"AnalyticsAPI"
    },
    "message":"The calling client sent a bad request to the service.",
    "source":"AnalyticsAPI"
}

以上是舉例比較多人會想要看的内容,還有其他的 APIs 可以參考:

[範例程式]

DotblogsSampleCode - DevCenterAnalysisAPI (GitHub)

======

以上是介紹怎麽搭配 Azure AD Application 將 App 的一些分析資料給截取出來,省掉每次都需要登入到 Dev Center 才能看到資料。

以上 demo 的範例衹是一些由 Dev Center 所記錄的常用分析資料,如果需要更進一步,可參考<學習 Application Insights 協助記錄 Apps 的相關動作>爲 App 加入一些記錄點,做更詳細的資料匯出與分析。

 

References: