[Windows Phone][Store] 定期檢查 App 在各國市集架上的狀況

App 無預警遭到下架的狀況時有所聞,原因可能是政策變更,也可能是官方內部作業的疏失。不論原因如何,為了能在第一時間發現 app 搜尋不到或不在架上的問題,好跟官方聯繫取得協助,有必要將自動監測 App 在各國市集架上狀況的機制建立起來。

不過 Windows Phone Store 並未提供像 Apple Search API 之類的工具,要透過程式查詢 app 在架上的狀況,似乎只能尋求 Web scraping 的管道?

所幸有人利用 Fiddler 側錄 Windows Phone 實機往 Store 的連線,發現有未公開的 API 可以完成這 件事。

跟監測機制相關的 API 有:

用關鍵字可以找到 app
http://marketplaceedgeservice.windowsphone.com/v8/catalog/apps?os=<OS>&cc=<COUNTRY>&oc=&lang=<LANG>&hw=469838850&dm=Virtual&moId=&chunkSize=10&cf=&q=<QUERY>
確認 app 還在該國市集架上
http://marketplaceedgeservice.windowsphone.com/v8/catalog/apps/<APPID>?os=<OS>&cc=<COUNTRY>&oc=&lang=<LANG>&hw=469838850&dm=Virtual&oemId=&moId=&cf=

其中:

  • QUERY – 搜尋 app 用的關鍵字。

  • APPID – App ID,可以從 Store 的網址列取得。例如 Facebook 的 ID 是 82a23635-5bd9-df11-a844-00237de2db9e

  • OS – Windows Phone 作業系統的版號,可以從這這裡取得,例如 8.0.9903.08.10.12359.845 (Blue) 等。

  • COUNTRY – Country Code (ISO 3166-1 alpha-2),例如 TW (Taiwan)、JP (Japan) 等。

  • LANG – Language Code,可以參考各國 Windows Phone Store 網址內含的 code。例如 zh-tw (Taiwan)、ja-jp (Japan) 等。

簡單說明上面兩個 API 的 response,以 Facebook 為例:

<?xml version="1.0" encoding="UTF-8"?>
<a:feed xmlns:a="http://www.w3.org/2005/Atom" xmlns="http://schemas.zune.net/catalog/apps/2008/02" xmlns:os="http://a9.com/-/spec/opensearch/1.1/">
   <a:link rel="next" type="application/atom+xml" href="/v8/catalog/apps?q=facebook&amp;startIndex=10&amp;chunkSize=10&amp;os=8.10.12359.845&amp;cc=TW&amp;oc=&amp;lang=zh-tw&amp;hw=469838850&amp;dm=Virtual&amp;moId=&amp;cf=" />
   <a:link rel="self" type="application/atom+xml" href="/v8/catalog/apps?q=facebook&amp;chunkSize=10&amp;os=8.10.12359.845&amp;cc=TW&amp;oc=&amp;lang=zh-tw&amp;hw=469838850&amp;dm=Virtual&amp;moId=&amp;cf=" />
   <os:startIndex>0</os:startIndex>
   <os:totalResults>11</os:totalResults>
   <os:itemsPerPage>10</os:itemsPerPage>
   <a:updated>2014-09-03T10:42:39.677862Z</a:updated>
   <a:title type="text">List Of Items</a:title>
   <a:id>tag:catalog.zune.net,2014-09-03:/apps</a:id>
   <impressionId>d83e53597d10438a927aba19109f8e5f:API.BDIGeneric:MMKTSE</impressionId>
   <a:entry>
      <a:updated>2014-09-03T10:42:39.677862Z</a:updated>
      <a:title type="text">Facebook</a:title>
      <a:id>urn:uuid:82a23635-5bd9-df11-a844-00237de2db9e</a:id> <!-- 1 -->
1 App ID 可以用來判斷是否出現在搜尋結果裡。
<a:feed xmlns:a="http://www.w3.org/2005/Atom" xmlns="http://schemas.zune.net/catalog/apps/2008/02" xmlns:os="http://a9.com/-/spec/opensearch/1.1/">
   <a:link rel="self" type="application/atom+xml" href="/v8/catalog/apps/82a23635-5bd9-df11-a844-00237de2db9e?os=8.10.12359.845&amp;cc=TW&amp;oc=&amp;lang=zh-tw&amp;hw=469838850&amp;dm=Virtual&amp;oemId=&amp;moId=&amp;cf=" />
   <a:updated>2014-09-03T10:48:26.284222Z</a:updated>
   <a:title type="text">Facebook</a:title>
   <a:id>urn:uuid:82a23635-5bd9-df11-a844-00237de2db9e</a:id>
   <!-- ... -->
   <a:entry>
      <a:updated>2014-09-03T10:48:26.284222Z</a:updated>
      <a:title type="text">Facebook 8.3.1.0</a:title>
      <a:id>urn:uuid:e30fc3d4-90fe-43bf-8d5d-5a2641cf6980</a:id>
      <version>8.3.1.0</version>
      <payloadId>urn:uuid:fd140287-c97f-49da-9c82-86515bf8eec6</payloadId>
      <skuId>urn:uuid:e30fc3d4-90fe-43bf-8d5d-5a2641cf6980</skuId>
      <skuLastUpdated>2014-08-04T13:24:11.843000Z</skuLastUpdated>
      <isAvailableInCountry>true</isAvailableInCountry> <!-- 1 -->
      <isAvailableInStore>true</isAvailableInStore>
      <isClientTypeCompatible>true</isClientTypeCompatible>
      <isHardwareCompatible>true</isHardwareCompatible>
      <isBlacklisted>false</isBlacklisted>
1 <isAvailableInStore/><isAvailableInCountry/> 可以分別拿來檢查 “是否在架上" 與 “是否在該國市集上架"。

下面的 unit test 可以測試 Facebook 是否在 Windows Phone 台灣市集的架上:

import unittest2 as unittest, urllib
from xml.etree import ElementTree as ET
from xml.etree.ElementTree import QName

APPID = '82a23635-5bd9-df11-a844-00237de2db9e'
URL_SEARCH = 'http://marketplaceedgeservice.windowsphone.com/v8/catalog/apps?os=8.10.12359.845&cc=TW&oc=&lang=zh-tw&hw=469838850&dm=Virtual&moId=&chunkSize=10&cf=&q=facebook'
URL_APP = 'http://marketplaceedgeservice.windowsphone.com/v8/catalog/apps/82a23635-5bd9-df11-a844-00237de2db9e?os=8.10.12359.845&cc=TW&oc=&lang=zh-tw&hw=469838850&dm=Virtual&oemId=&moId=&cf='

NS_ZUNE = 'http://schemas.zune.net/catalog/apps/2008/02'
NS_ATOM = 'http://www.w3.org/2005/Atom'

class FacebookWPStoreTest(unittest.TestCase):

    def test_available_in_store(self):
        # found in the search result
        root = ET.fromstring(urllib2.urlopen(URL_SEARCH).read())

        # <a:id>urn:uuid:82a23635-5bd9-df11-a844-00237de2db9e</a:id>
        id_tag = QName(NS_ATOM, 'id')
        ids = [_.text for _ in root.findall('.//%s' % id_tag)]
        self.assertIn('urn:uuid:%s' % APPID, ids)

        # available in store and country
        root = ET.fromstring(urllib2.urlopen(URL_APP).read())

        # <isAvailableInCountry>true</isAvailableInCountry>
        # <isAvailableInStore>true</isAvailableInStore>
        country_tag = QName(NS_ZUNE, 'isAvailableInCountry')
        store_tag = QName(NS_ZUNE, 'isAvailableInStore')
        self.assertEqual(root.find('.//%s' % country_tag).text, 'true')
        self.assertEqual(root.find('.//%s' % store_tag).text, 'true')

if __name__ == '__main__':
    unittest.main()
廣告

發表迴響

在下方填入你的資料或按右方圖示以社群網站登入:

WordPress.com Logo

您的留言將使用 WordPress.com 帳號。 登出 / 變更 )

Twitter picture

您的留言將使用 Twitter 帳號。 登出 / 變更 )

Facebook照片

您的留言將使用 Facebook 帳號。 登出 / 變更 )

Google+ photo

您的留言將使用 Google+ 帳號。 登出 / 變更 )

連結到 %s