App Store Connect API

背景

WWDC 2018 蘋果把名字iTunes Connect修改成App Store Connect,同時推出了App Store Connect API,用於自動化一些App Store Connect後臺操做:html

  • 管理證書、管理配置文件、管理設備和安裝包ID
  • 管理用戶、設置用戶角色以及app的訪問權限
  • 管理TestFlight、公測用戶以及公開連接、查看app的build二進制包信息
  • 下載財務和銷售報告

最近後臺同事問我,可否經過接口從蘋果後臺獲取銷售記錄(下載量),方便分析和統計。因爲網絡上關於App Store Connect API的資料甚少,藉此機會我自行研究了一下,並用寫下這篇博客,算是給「App Store Connect API」關鍵字貢獻一份力量吧(捂臉)。android

本文主要介紹App Store Connect API,關於如何自動獲取蘋果後臺的銷售報告,見下一篇文章《如何自動化獲取AppStore的銷售和趨勢報告》git

Spaceship VS App Store Connect API

在介紹App Store Connect API以前我想說一下Fastlane,感受Fastlane比App Store Connect API出名多了,關注的人也更多。
Fastlane是一套用Ruby開發的,用於解決iOS和Android自動化編譯打包、上傳、發佈等的解決方案。
Spaceship是Fastlane的一個子工具,提供了一套Apple Developer CenterApp Store Connect 的API。github

Spaceship很是強大,全部你在瀏覽器上對Apple Developer Center 和 App Store Connect的操做幾乎均可以經過Spaceship命令解決,全部App Store Connect API能實現的功能,Spaceship幾乎都能實現,有些App Store Connect API沒有的功能,Spaceship也能實現。
Spaceship的原理:經過模擬網頁操做,分析和抓取網頁的接口和數據來實現相應功能。能夠參見Technical Details
sql

Spaceship使用到的蘋果API

Spaceship這麼強大,直接用Spaceship不就好了麼。Spaceship固然也有它的缺點。json

Spaceship

優勢windows

  • 功能強大。幾乎全部你在瀏覽器上對Apple Developer Center 和 App Store Connect的操做均可以經過Spaceship命令解決。
  • cookie有效期比較長。上面講了Spaceship的原理是模擬網頁請求,因此得先登陸(帳號、密碼),登陸後cookie保留在本地,有效期一個月,cookie失效前請求API不須要在登陸。

缺點api

  • 須要登陸兩次。Apple Developer Center 和 App Store Connect 須要分別登陸,一方生成的cookie對另外一方可能無論用。
  • 雙重認證。若是你的開發者帳號開了雙重認證,那登陸的時候還須要驗證碼。驗證碼這個東西使總體可用性大大下降。
  • 對Window系統支持不友好。Spaceship是Fastlane的子工具,是Ruby開發的,須要Unix(Mac)環境。有人說Window上也能夠跑Ruby。你們能夠自行嘗試
  • 非官方API。由於是非官方API,因此後續若是蘋果有改動,可能就用不了了,得Spaceship做者及時更新才行。

App Store Connect API

優勢數組

  • 不須要登陸。App Store Connect API是利用私鑰生成token來訪問API的。不須要提供開發者帳號密碼,相對也更安全。
  • REST API。App Store Connect API是REST API,這決定了其調用更方便,不受操做系統等限制。
  • 官方API。維護有保障,即便後續蘋果調整了網頁內容,其相應API也不會受影響。

缺點瀏覽器

  • 功能受限。App Store Connect官方文檔列出來的API很少,其實還有不少操做蘋果都沒有提供相應的API,這使得可用性下降,只能期盼後期蘋果能多開放一些API。
  • token有效期較短。token有效期只有20分鐘,過時後得從新生成token。

生成 App Store Connect API token

App Store Connect API每一個請求都須要在請求頭中攜帶token,要想使用App Store Connect API,首先得知道如何生成token。
token是經過App Store Connect後臺生成的密鑰簽名JWT(下文介紹)產生的。

生成密鑰(手動操做,只需作一次)

1.請求App Store Connect API訪問權限。
App Store Connect後臺,「用戶和訪問」 - 「密鑰」,點擊「請求訪問權限」。只有agent纔有權限

2.生成密鑰。
申請訪問權限後,纔會看到「生成密鑰」的按鈕,點擊「生成密鑰」,根據提示起個名字,完成後會產生一個「Issuer ID」和「密鑰ID」,這兩個參數後面生成token須要用到。下載密鑰,密鑰是一個.p8的文件,注意:私鑰只能下載一次,永遠不會過時,保管好,若是丟失了,去App Store Connect後臺撤銷密鑰,不然別人拿到也能夠用。

生成token(用代碼生成,有效期20分鐘,失效後須要再次生成)

App Store Connect API使用的token採用的是JSON Web Token(JWT)標準,蘋果文檔介紹了建立JWT並用密鑰簽名生成token的過程。
不過這裏你們能夠直接去JWT.io下載各類語言的開源庫來生成token。

下面是WWDC上蘋果貼的Ruby代碼,我稍做了修改。執行下方Ruby代碼便可生成一條token(自行替換 ISSUER_ID、KEY_ID、P8_PATH這三個參數,下面代碼中貼的是蘋果文檔上的值)

#生成 App Store Connect API用的token

require "base64"
require "jwt"

ISSUER_ID = "57246542-96fe-1a63-e053-0824d011072a"    #ISSUER_ID(App Store Connect後臺獲取)
KEY_ID = "2X9R4HXF34"                                 #密鑰ID(App Store Connect後臺獲取)
P8_PATH= "/Users/Documents/test_AuthKey_22xxxxxxxx.p8"    #密鑰文件路徑(本地PC文件路徑)

private_key = OpenSSL::PKey.read(File.read(P8_PATH))

token = JWT.encode(
   {

    iss: ISSUER_ID,
    exp: Time.now.to_i + 20 * 60,    #最多20分鐘,設置多了生成的token是無效的
    aud: "appstoreconnect-v1"
   },
   private_key,
   "ES256",
   header_fields={
     kid: KEY_ID }
 )
puts token
複製代碼

使用token

調用App Store Connect API時添加下列請求頭
'Authorization: Bearer [signed token]'
"Bearer"是固定寫法,把[signed token]換成你的token,注意,Bearer和token中間有空格
下面是個例子
curl -v -H 'Authorization: Bearer [signed token]' "https://api.appstoreconnect.apple.com/v1/apps"
token有效期是20分鐘,token過時後API會報錯,說受權無效。須要從新生成一個新的token使用。
我嘗試在JWT配置中讓token有效期超過20分鐘,可是失敗了,這樣雖然能夠生成token,但用token發起請求會報錯,說token無效,看來token最多隻能20分鐘。

App Store Connect API 部分API介紹

下面介紹部分API功能,你們可自行查看App Store Connect API官方文檔查看其它功能。(這裏想吐槽一下蘋果的文檔,真的簡潔的不能在簡潔了,數據結構層次也不夠直觀,請求參數、返回響應一個示例都沒有給,各個參數表明什麼意思也不說明一下,徹底靠猜靠試,用戶體驗很很差)。下面我列出了注意事項,是我對照官方文檔反覆嘗試後的總結,相信對你閱讀蘋果文檔會有幫助。

注意事項:

  • 建立接口,請求參數中的id字段,並非平時咱們用到的uuid,bundle identifier等字段,而是查詢和建立接口返回的「隱式」id字段,注意區分。
  • 查詢接口,可選參數fields,表示查詢結果展現哪些字段,相似sql語句的查詢字段,默認是所有。
  • 查詢接口,可選參數filter,表示查詢某個特定結果,相似sql語句的where,注意,這是模糊查詢,效果是contain,而不是match,因此可能查到多條。(怎麼精確查找,我也不知道,若是你知道請告知我)
  • 查詢接口,可選參數include,表示是否關聯某個字段詳情到響應體中,默認不包含。好比查詢profile列表,並不會返回bundle ID,certificates,devices的信息,(連id都不會返回,只會返回links)。請求參數加上 include=bundleId,certificates,devices 後就會返回這些數據了,加上後會新增included字段返回關聯字段的詳細信息。
  • 下載文件,部分查詢接口會返回文件內容,好比certificates、profile等,是以base64字符串形式返回的。若有須要可自行解碼成文件。參考命令echo 「MIIFnDCC..BISgAwIBAgII」 | base64 -D > a.cer

假設下面介紹的請求默認都帶了token請求頭的。

Device

獲取設備信息

可選參數:
fields[devices]:篩選顯示的數據,addedDate, deviceClass, model, name, platform, status, udid
filter[id]
filter[name]
filter[platform]:IOS, MAC_OS
filter[status]:ENABLED, DISABLED
filter[udid]:
limit:integer,最大200
sort:id, -id, name, -name, platform, -platform, status, -status, udid, -udid

獲取設備列表
GET https://api.appstoreconnect.apple.com/v1/devices

獲取某個設備信息(列表API追加id路徑)
GET https://api.appstoreconnect.apple.com/v1/devices/539US4VFVK

獲取設備列表 返回數據
{
  "data": [{
    "type": "devices",
    "id": "539US4XXXX",
    "attributes": {
      "addedDate": "2019-07-02T13:11:10.000+0000",
      "name": "random1",
      "deviceClass": "IPHONE",
      "model": "iPhone 6s",
      "udid": "e05a144e8ef31c50f12xxxxxxxxxxx",
      "platform": "IOS",
      "status": "ENABLED"
    },
    "links": {
      "self": "https://api.appstoreconnect.apple.com/v1/devices/539US4XXXX"
    }
  }, {
    "type": "devices",
    "id": "W9W337XXXX",
    "attributes": {
      "addedDate": "2019-11-08T10:46:34.000+0000",
      "name": "test_se",
      "deviceClass": "IPHONE",
      "model": null,
      "udid": "f51f5b7c677565cfa629xxxxxxxxxxxxx",
      "platform": "IOS",
      "status": "ENABLED"
    },
    "links": {
      "self": "https://api.appstoreconnect.apple.com/v1/devices/W9W337XXXX"
    }
  }],
  "links": {
    "self": "https://api.appstoreconnect.apple.com/v1/devices"
  },
  "meta": {
    "paging": {
      "total": 2,
      "limit": 20
    }
  }
}
複製代碼

註冊一個設備

添加請求頭 'Content-Type: application/json'
POST https://api.appstoreconnect.apple.com/v1/devices
必傳參數:(其它沒列出來的參數表示寫法固定,參考請求示例)
platform:IOS,MAC_OS
name:取個名字
udid:設備標識
Status Code: 201 Created表示成功。

請求示例
{
    "data": {
        "attributes": {
            "name": "test_se",
            "udid": "f51f5b7c677565cfa629xxxxxxxxx",
            "platform": "IOS"
        },
        "type": "devices"
    }
}

返回數據
{
  "data": {
    "type": "devices",
    "id": "W9W337XXXX",
    "attributes": {
      "addedDate": "2019-11-08T10:46:34.781+0000",
      "name": "test_se",
      "deviceClass": "IPHONE",
      "model": null,
      "udid": "f51f5b7c677565cfa629xxxxxxxxx",
      "platform": "IOS",
      "status": "ENABLED"
    },
    "links": {
      "self": "https://api.appstoreconnect.apple.com/v1/devices/W9W337XXXX"
    }
  },
  "links": {
    "self": "https://api.appstoreconnect.apple.com/v1/devices"
  }
}
複製代碼

刪除一個設備

刪除設備只能在開發者網站操做,沒有提供API。(這句話是蘋果文檔上寫的)

Bundle IDs

建立bundle id

添加請求頭 'Content-Type: application/json'
POST https://api.appstoreconnect.apple.com/v1/bundleIds
必傳參數:(其它沒列出來的參數表示寫法固定,參考請求示例)
name:取個名字
identifier:bundle identifier
seedId:Team ID
platform:IOS,MAC_OS
Status Code: 201 Created,表示成功

請求示例
{
    "data": {
        "attributes": {
            "name": "bundlieAPITest",
            "identifier": "cosw.bundlieAPI_test",
            "seedId": "U8FBXXXXXX",
            "platform": "IOS"
        },
        "type": "bundleIds"
    }
}
返回數據
{
    "data": {
        "type": "bundleIds",
        "id": "Q9XMDVCXXX",
        "attributes": {
            "name": "bundlieAPITest",
            "identifier": "cosw.bundlieAPI_test",
            "platform": "IOS",
            "seedId": "U8FBXXXXXX"
        },
        "relationships": {...省略},
        "links": {
            "self": "https://api.appstoreconnect.apple.com/v1/bundleIds/Q9XMDVCXXX"
        }
    },
    "links": {
        "self": "https://api.appstoreconnect.apple.com/v1/bundleIds"
    }
}

複製代碼

獲取bundle id列表

可選參數:
fields[bundleIds]:attributes字段篩選顯示結果,bundleIdCapabilities, identifier, name, platform, profiles, seedId
fields[profiles]:profiles字段篩選顯示結果,bundleId, certificates, createdDate, devices, expirationDate, name, platform, profileContent, profileState, profileType, uuid
filter[id]:
filter[identifier]:
filter[name]:
filter[platform]:IOS, MAC_OS
filter[seedId]:
include:bundleIdCapabilities, profiles
limit:integer,最大200
limit[profiles]:integer,最大50
sort:id, -id, name, -name, platform, -platform, seedId, -seedId
fields[bundleIdCapabilities]:bundleId, capabilityType, settings

獲取bundle id列表
GET https://api.appstoreconnect.apple.com/v1/bundleIds

獲取bundle id列表(精簡版,去掉了不少不須要的數據)
GET https://api.appstoreconnect.apple.com/v1/bundleIds?fields[bundleIds]=name,identifier,platform

查找identifier爲com.tencent.xin的bundle id(注意這裏是模糊查找,好比com.tencent.xin、com.tencent.xin1004都會被列出來)
GET https://api.appstoreconnect.apple.com/v1/bundleIds?fields[bundleIds]=name,identifier,platform&filter[identifier]=com.tencent.xin

獲取bundle id列表(精簡版) 返回數據
{
    "data": [
        {
            "type": "bundleIds",
            "id": "2795XXXXX",
            "attributes": {
                "name": "XC com.tencent.xin1004",
                "identifier": "com.tencent.xin1004",
                "platform": "IOS"
            },
            "links": {
                "self": "https://api.appstoreconnect.apple.com/v1/bundleIds/2795XXXXX"
            }
        },
        {
            "type": "bundleIds",
            "id": "39VMXXXXX",
            "attributes": {
                "name": "wechat",
                "identifier": "com.tencent.xin",
                "platform": "IOS"
            },
            "links": {
                "self": "https://api.appstoreconnect.apple.com/v1/bundleIds/39VMXXXXX"
            }
        }
    ],
    "links": {
        "self": "https://api.appstoreconnect.apple.com/v1/bundleIds?fields%5BbundleIds%5D=name%2Cidentifier%2Cplatform"
    },
    "meta": {
        "paging": {
            "total": 4,
            "limit": 20
        }
    }
}
複製代碼

刪除一個 bundle id

DELETE https://api.appstoreconnect.apple.com/v1/bundleIds/{id}
例如
https://api.appstoreconnect.apple.com/v1/bundleIds/2795XXXXX
成功,Status Codes:204 No Content
注意,刪除DELETE,而不是POST(後面全部的刪除API都符合這一條)

證書

建立證書

添加請求頭 Content-Type: application/json
POST https://api.appstoreconnect.apple.com/v1/certificates
必傳參數:(其它沒列出來的參數表示寫法固定,參考請求示例)
csrContent:CSR文件的內容。建立好.csr文件(你能夠用 鑰匙串-證書助理 來生成CSR文件,或者用代碼生成)後,使用命令 cat a.csr,打印出.csr的內容,做爲參數賦值。注意:打印出來的內容帶有換行符,得把換行符去掉後在賦值,不然會報錯。
certificateType:證書類型,IOS_DEVELOPMENT,IOS_DISTRIBUTION,MAC_APP_DISTRIBUTION,MAC_INSTALLER_DISTRIBUTION,MAC_APP_DEVELOPMENT,DEVELOPER_ID_KEXT,DEVELOPER_ID_APPLICATION
成功,Status Code: 201 Created

請求參數
{
    "data": {
        "attributes": {
            "csrContent": "SDADAD12...3dSD123",
            "certificateType": "IOS_DEVELOPMENT"
        },
        "type": "certificates"
    }
}

複製代碼

下圖是用cat命令打印 .csr 文件後的效果,取出BEGIN和END中間那一段,再去掉每行末尾的換行符就是csrContent參數值。在線過濾換行符

打印.csr文件

我寫了段代碼,傳入.csr文件路徑,能夠輸出處理後的csrContent值,你們能夠參考。

#從.csr文件取csrContent值(取第二行到倒數第二行的內容,再去掉換行符)
csrFile='/Users/Cocoakier/Movies/CertificateSigningRequest.certSigningRequest'
line=$[`cat $csrFile | wc -l`-1]
cat $csrFile | sed -n "2,$line""p" | awk 'BEGIN{ORS=""}{print $0}'
複製代碼

獲取證書信息(下載證書)

可選參數:
fields[certificates]:certificateContent(證書文件), certificateType, csrContent, displayName, expirationDate, name, platform, serialNumber
filter[id]:
filter[serialNumber]:
limit,最大200
sort:certificateType, -certificateType, displayName, -displayName, id, -id, serialNumber, -serialNumber
filter[certificateType]:IOS_DEVELOPMENT, IOS_DISTRIBUTION, MAC_APP_DISTRIBUTION, MAC_INSTALLER_DISTRIBUTION, MAC_APP_DEVELOPMENT, DEVELOPER_ID_KEXT, DEVELOPER_ID_APPLICATION
filter[displayName]:

獲取證書列表
GET https://api.appstoreconnect.apple.com/v1/certificates

返回數據
{
  "data": [{
    "type": "certificates",
    "id": "5DW7PXXXX",
    "attributes": {
      "serialNumber": "1D0160EEXXXXXX",
      "certificateContent": "MIIFnDCCBISgAwIBAgIIHQFg7.....4Y2CP+fCYEpTEjXlQtJbOGjaXgwjAIdPhu",
      "displayName": "xiao ming",
      "name": "iOS Development: xiao ming",
      "csrContent": null,
      "platform": "IOS",
      "expirationDate": "2020-03-28T11:43:19.000+0000",
      "certificateType": "IOS_DEVELOPMENT"
    },
    "links": {
      "self": "https://api.appstoreconnect.apple.com/v1/certificates/5DW7PXXXX"
    }
  }, {
    "type": "certificates",
    "id": "D89QXXXXX",
    "attributes": {
      "serialNumber": "39E252BXXXXXX",
      "certificateContent": "MIIFnzCCBIegAwIBAgIIOeJ.....o5zB1YPJtvfX49H2n",
      "displayName": "xiao ming",
      "name": "iOS Distribution: xiao ming",
      "csrContent": null,
      "platform": "IOS",
      "expirationDate": "2020-04-22T11:56:35.000+0000",
      "certificateType": "IOS_DISTRIBUTION"
    },
    "links": {
      "self": "https://api.appstoreconnect.apple.com/v1/certificates/D89QXXXXX"
    }
  }],
  "links": {
    "self": "https://api.appstoreconnect.apple.com/v1/certificates"
  },
  "meta": {
    "paging": {
      "total": 2,
      "limit": 20
    }
  }
}
複製代碼

下載證書
上面接口返回的字段中,certificateContent就是證書文件,蘋果是以base64的方式經過接口返回的。咱們base64解碼一下就能夠還原成.cer的文件了。

certificateContent="MIIFnDCCBISgAwIB...uG4Y2CP+fCYEpTEjXlQtJbOGjaXgwjAIdPhu"
echo $certificateContent | base64 -D > '/Users/Cocoakier/Movies/a.cer'
複製代碼

刪除證書

DELETE https://api.appstoreconnect.apple.com/v1/certificates/{id}
例如
DELETE https://api.appstoreconnect.apple.com/v1/certificates/5DW7PXXXX
成功,Status Codes:204 No Content

Provisioning

獲取Provisioning信息(下載)

可選參數:
fields[profiles]:bundleId, certificates, createdDate, devices, expirationDate, name, platform, profileContent(provisioning文件), profileState, profileType, uuid
fields[certificates]:certificateContent, certificateType, csrContent, displayName, expirationDate, name, platform, serialNumber
fields[devices]:addedDate, deviceClass, model, name, platform, status, udid
fields[bundleIds]:bundleIdCapabilities, identifier, name, platform, profiles, seedId
filter[id]:
filter[name]:
filter[profileState]:ACTIVE, INVALID
filter[profileType]:IOS_APP_DEVELOPMENT, IOS_APP_STORE, IOS_APP_ADHOC, IOS_APP_INHOUSE, MAC_APP_DEVELOPMENT, MAC_APP_STORE, MAC_APP_DIRECT, TVOS_APP_DEVELOPMENT, TVOS_APP_STORE, TVOS_APP_ADHOC, TVOS_APP_INHOUSE
include:是否返回具體信息(默認不返回),bundleId, certificates, devices
limit:最大200
limit[certificates]:最大50
limit[devices]:最大50
sort:id, -id, name, -name, profileState, -profileState, profileType, -profileType

獲取Provisioning列表 普通版(不包含bundleId、certificates、devices信息)
GET https://api.appstoreconnect.apple.com/v1/profiles

獲取Provisioning列表 增強版(包含bundleId、certificates、devices信息)
GET https://api.appstoreconnect.apple.com/v1/profiles?include=bundleId,certificates,devices

獲取某個Provisioning devices詳情(列表API+profiles id+devices)
GET https://api.appstoreconnect.apple.com/v1/profiles/295XXXXX/devices

獲取某個Provisioning certificates詳情
GET https://api.appstoreconnect.apple.com/v1/profiles/295XXXXX/certificates

獲取某個Provisioning bundleId詳情
GET https://api.appstoreconnect.apple.com/v1/profiles/295XXXXX/bundleId

獲取Provisioning列表 普通版(不包含bundleId、certificates、devices信息) 返回數據
{
    "data": [
        {
            "type": "profiles",
            "id": "295XXXXX",
            "attributes": {
                "profileState": "ACTIVE",
                "createdDate": "2019-03-29T11:54:58.000+0000",
                "profileType": "IOS_APP_DEVELOPMENT",
                "name": "test_dev",
                "profileContent": "MIId9AYJKoZIhvcNAQcC..省略N多字...Syr5TPmPe1DiY4w==",
                "uuid": "1d2xxxxxx-f764-4c71-xxxx-1d77xxxxxxxx",
                "platform": "IOS",
                "expirationDate": "2020-03-28T11:54:58.000+0000"
            },
            "relationships": {...省略沒用的信息}
        }
    ]
}

獲取Provisioning列表 增強版(包含bundleId、certificates、devices信息) 返回數據(數據太多,我刪除了一些無用字段)
{
    "data": [
        {
            "type": "profiles",
            "id": "295XXXXX",
            "attributes": {
                "profileState": "ACTIVE",
                "createdDate": "2019-03-29T11:54:58.000+0000",
                "profileType": "IOS_APP_DEVELOPMENT",
                "name": "test_dev",
                "profileContent": "MIId9AYJKoZIhvcNAQcC..省略N多字...Syr5TPmPe1DiY4w==",
                "uuid": "1d2xxxxxx-f764-4c71-xxxx-1d77xxxxxxxx",
                "platform": "IOS",
                "expirationDate": "2020-03-28T11:54:58.000+0000"
            }
        }
    ],
    "included": [
        {
            "type": "certificates",
            "id": "5DWXXXXXX",
            "attributes": {
                "serialNumber": "1D0160XXXXXXX",
                "certificateContent": "MIIFnDCC...省略N多字...BIXgwjAIdPhu",
                "displayName": "xiao ming",
                "name": "iOS Development: xiao ming",
                "csrContent": null,
                "platform": "IOS",
                "expirationDate": "2020-03-28T11:43:19.000+0000",
                "certificateType": "IOS_DEVELOPMENT"
            }
        },
        {
            "type": "devices",
            "id": "KD88XXXXXX",
            "attributes": {
                "addedDate": "2019-03-29T11:48:47.000+0000",
                "name": "xiaoming_5s",
                "deviceClass": "IPHONE",
                "model": "iPhone 5s (Model A1457, A1518, A1528, A1530)",
                "udid": "61262034b932dxxxxxxxxxxxxxxx",
                "platform": "IOS",
                "status": "ENABLED"
            }
        },
        {
            "type": "devices",
            "id": "5CXUXXXXXX",
            "attributes": {
                "addedDate": "2019-03-29T11:49:04.000+0000",
                "name": "xiaohong_iPhoneX",
                "deviceClass": "IPHONE",
                "model": null,
                "udid": "f51f5b7c677565cxxxxxxxxxxxxxx",
                "platform": "IOS",
                "status": "ENABLED"
            }
        },
        {
            "type": "bundleIds",
            "id": "7RZ4XXXXX",
            "attributes": {
                "name": "wechat",
                "identifier": "com.tencent.xin",
                "platform": "IOS",
                "seedId": "9RDXXXXXX"
            }
        }
    ]
}
複製代碼

下載provisioning文件
上面接口返回的字段中,profileContent字段的值就是provisioning文件,和證書同樣,蘋果是以base64的方式經過接口返回的。咱們base64解碼一下就能夠還原成.mobileprovision的文件了。

profileContent="MIId9AYJKoZIhvcNAQcC..省略..Syr5TPmPe1DiY4w=="
echo $profileContent | base64 -D > '/Users/Cocoakier/Movies/test.mobileprovision'
複製代碼

注意:若是profile文件無效(profileState=INVALID),接口返回數據中profileContent的值可能爲null。

建立一個Provisioning

添加請求頭 'Content-Type: application/json’
POST https://api.appstoreconnect.apple.com/v1/profiles
必傳參數:(其它沒列出來的參數表示寫法固定,參考請求示例)
name:起個名字
profileType:IOS_APP_DEVELOPMENT, IOS_APP_STORE, IOS_APP_ADHOC, IOS_APP_INHOUSE, MAC_APP_DEVELOPMENT, MAC_APP_STORE, MAC_APP_DIRECT, TVOS_APP_DEVELOPMENT, TVOS_APP_STORE, TVOS_APP_ADHOC, TVOS_APP_INHOUSE
(bundleId)id:bundle id,是建立或查詢接口返回的那個id不是bundle identider,注意區分!
(certificates)id:證書id,能夠傳多個,外層是數組
(devices)id:設備id(profileType=IOS_APP_STORE時不傳),能夠傳多個,外層是數組。注意,這裏的設備id不是平時用的udid,是建立或查詢接口返回的那個id!
成功,Status Code: 201 Created

請求示例
{
    "data": {
        "attributes": {
            "name": "test_se",
            "profileType": "IOS_APP_DEVELOPMENT"
        },
        "type": "profiles",
        "relationships": {
            "bundleId": {
                "data": {
                    "id": "TH9XXXX",
                    "type": "bundleIds"
                }
            },
            "certificates": {
                "data": [
                    {
                        "id": "5DWXXXXX",
                        "type": "certificates"
                    }
                ]
            },
            "devices": {
                "data": [
                    {
                        "id": "7BUHXXXXX",
                        "type": "devices"
                    }
                ]
            }
        }
    }
}

返回數據(去除了一些無用數據)
{
  "data": {
    "type": "profiles",
    "id": "YFV93T5866",
    "attributes": {
      "profileState": "ACTIVE",
      "createdDate": "2019-11-12T13:00:11.605+0000",
      "profileType": "IOS_APP_DEVELOPMENT",
      "name": "test_se",
      "profileContent": 「MIId9AYJKoZIhvcNAQcCoII..省略...e1DiY4w==", "uuid": "7bbxxxxx-8c21-4xxx-9cc9-3485xxxxx", "platform": "IOS", "expirationDate": "2020-11-11T13:00:11.605+0000" }, "relationships": { "bundleId": { "data": { "type": "bundleIds", "id": "TH9XXXX" }, }, "certificates": { "data": [{ "type": "certificates", "id": "5DWXXXXX" }], }, "devices": { "data": [{ "type": "devices", "id": "7BUHXXXXX" }], } }, }, } 複製代碼

刪除provisioning**

DELETE https://api.appstoreconnect.apple.com/v1/profiles/{id}
例如
DELETE https://api.appstoreconnect.apple.com/v1/profiles/YFV93T5866
成功,Status Codes:204 No Content

User

獲取開發者團隊成員列表

GET https://api.appstoreconnect.apple.com/v1/users
可選參數:
fields[apps]:betaAppLocalizations, betaAppReviewDetail, betaGroups, betaLicenseAgreement, betaTesters, builds, bundleId, name, preReleaseVersions, primaryLocale, sku
fields[users]:allAppsVisible, firstName, lastName, provisioningAllowed, roles, username, visibleApps
include:visibleApps
limit:最大200
sort:lastName, -lastName, username, -username
filter[roles]:ADMIN, FINANCE, TECHNICAL, ACCOUNT_HOLDER, READ_ONLY, SALES, MARKETING, APP_MANAGER, DEVELOPER, ACCESS_TO_REPORTS, CUSTOMER_SUPPORT
filter[visibleApps]:
filter[username]:
limit[visibleApps]:最大50

返回數據
{
  "data": [{
    "type": "users",
    "id": "73xxx-09ef-4f4a-af23-abb3xxxxxxx",
    "attributes": {
      "username": "xiaoming@qq.com",
      "firstName": "xiao",
      "lastName": "ming",
      "roles": ["ADMIN", "ACCOUNT_HOLDER"],
      "allAppsVisible": true,
      "provisioningAllowed": true
    },
    "relationships": {
      "visibleApps": {
        "links": {
          "self": "https://api.appstoreconnect.apple.com/v1/users/73xxx-09ef-4f4a-af23-abb3xxxxxxx/relationships/visibleApps",
          "related": "https://api.appstoreconnect.apple.com/v1/users/73xxx-09ef-4f4a-af23-abb3xxxxxxx/visibleApps"
        }
      }
    },
    "links": {
      "self": "https://api.appstoreconnect.apple.com/v1/users/73xxx-09ef-4f4a-af23-abb3xxxxxxx"
    }
  }],
  "links": {
    "self": "https://api.appstoreconnect.apple.com/v1/users"
  },
  "meta": {
    "paging": {
      "total": 1,
      "limit": 50
    }
  }
}
複製代碼

TestFlight

獲取APP列表

GET https://api.appstoreconnect.apple.com/v1/apps
可選參數:
fields[apps]:返回的app信息有限,就是後面這些,builds, bundleId, name, preReleaseVersions, primaryLocale, sku, betaAppLocalizations, betaAppReviewDetail, betaGroups, betaLicenseAgreement, betaTesters
include:betaAppLocalizations, betaAppReviewDetail, betaGroups, betaLicenseAgreement, builds, preReleaseVersions
其它可選參數,請自行查看文檔

獲取APP列表 返回數據(去除了一些無用字段)
{
  "data": [{
    "type": "apps",
    "id": "1456000000",
    "attributes": {
      "name": "微信",
      "bundleId": "com.tencent.xin",
      "sku": "com.tencent.xin",
      "primaryLocale": "zh-Hans"
    }
}
複製代碼

獲取某個app的preReleaseVersions信息(對應App Store Connect後臺的version)

GET https://api.appstoreconnect.apple.com/v1/apps/1456000000/preReleaseVersions

獲取某個app preReleaseVersions信息 返回數據(去除了一些無用數據)
{
  "data": [{
    "type": "preReleaseVersions",
    "id": "316bxxx-5394-46d7-8e49-4axxxxx",
    "attributes": {
      "version": "1.0.2",
      "platform": "IOS"
    }
  }, {
    "type": "preReleaseVersions",
    "id": "8a9xxxx-3620-4bbd-a540-9axxxxx",
    "attributes": {
      "version": "1.0.0",
      "platform": "IOS"
    },
  }, {
    "type": "preReleaseVersions",
    "id": "c649xxxx-3229-4e20-8349-2efaxxxxx",
    "attributes": {
      "version": "1.0.1",
      "platform": "IOS"
    }
  }],
  "meta": {
    "paging": {
      "total": 3,
      "limit": 50
    }
  }
}
複製代碼

獲取某個app的builds信息(對應App Store Connect後臺的二進制包)

GET https://api.appstoreconnect.apple.com/v1/apps/1456000000/builds

獲取某個app build信息 返回數據(我去掉了一些無用數據)
{
    "data": [
        {
            "type": "builds",
            "id": "977xxx-c0d1-47a5-b439-7485xxxx",
            "attributes": {
                "version": "5",
                "uploadedDate": "2019-07-05T01:49:16-07:00",
                "expirationDate": "2019-10-03T01:49:16-07:00",
                "expired": true,
                "minOsVersion": "9.0",
                "iconAssetToken": {
                    "templateUrl": "https://is2-ssl.mzstatic.com/image/thumb/Purple113/v4/41/24/46/41xxx-8fa3-142b-b3da-e1xxxxx/Icon-60@2x.png.png/{w}x{h}bb.{f}",
                    "width": 120,
                    "height": 120
                },
                "processingState": "VALID",
                "usesNonExemptEncryption": false
            },
        },
        {
            "type": "builds",
            "id": "de3d9xxx-d87b-449c-b025-a510xxxxx",
            "attributes": {
                "version": "6",
                "uploadedDate": "2019-11-04T00:13:03-08:00",
                "expirationDate": "2020-02-02T00:13:03-08:00",
                "expired": false,
                "minOsVersion": "9.0",
                "iconAssetToken": {
                    "templateUrl": "https://is4-ssl.mzstatic.com/image/thumb/Purple123/v4/4b/f2/41/4bxxx-f059-fe0a-c220-39cxxx/Icon-60@2x.png.png/{w}x{h}bb.{f}",
                    "width": 120,
                    "height": 120
                },
                "processingState": "VALID",
                "usesNonExemptEncryption": false
            }
        }
        ...
    ],
    "meta": {
        "paging": {
            "total": 6,
            "limit": 50
        }
    }
}
複製代碼

下載銷售和趨勢報告

《如何自動化獲取AppStore的銷售和趨勢報告》

總結

上述只列出了部分App Store Connnect API的功能,還有些功能,好比TestFlight、User、Bundle ID Capabilities等,沒有列出來。經過這篇文章想必你們對蘋果文檔的「風格」也熟悉了,其它功能能夠自行查閱官方文檔。給你們推薦一個JSON在線編輯工具,對照蘋果文檔構造請求體很好用。

總的來講,App Store Connect API目前能作的事情頗有限,主要仍是用於自動化管理證書、設備、bundle identifier這些,一些重要的接口蘋果仍然沒有開放,好比建立App,編輯元數據,提交審覈,查看審覈結果等,我想蘋果仍是考慮到安全問題吧,如今馬甲包原本就氾濫成災,若是開放了這些接口,後果可想而知。對於Mac平臺來講,Fastlane - Space 比 App Store Connect API 強大太多,App Store Connect API顯得有些雞肋了,可是對於Window平臺來講,App Store Connect API仍是不錯的選擇。

若是以爲這篇文章對你有幫助,請點個贊吧。若是有疑問能夠關注個人公衆號給我留言。
轉載請註明出處,謝謝!

參考連接:
App Store Connect的新特性(WWDC 2018 session 301 & 303)
App Store Connect API蘋果官方文檔
JWT官網
Spaceship官網
fastlane-windows-cannot-installing
openssl req 生成證書請求和自建CA

相關文章
相關標籤/搜索