グーペ カラーミーショップ ECブログリレー mobile GitHub Actions iOS

App Store Connect APIから新規DL数を取得

グーペ カラーミーショップ ECブログリレー mobile GitHub Actions iOS

この記事は EC ブログリレーの19日目の記事です。18日目はtagamyさんによるWebエンジニアがWindows 10を使うべき8つの理由でした。

こんにちは、Tatsumi0000です。業務では、iOSアプリの開発をしています。RxSwiftに苦戦しながら業務を進めています。

普段開発しているiOSアプリがどのくらいのDLされているか知りたくなることはありませんか? App Store Connectにログインすれば見れます。しかし、私は見に行くのは面倒だったので、毎朝10時に昨日のiOSアプリの新規DL数を投稿するSlackのbotを作成しました。新規DL数は、Apple公式のWeb APIである、App Store Connect APIから新規DL数を取得しています。動作環境としては、Go言語で書いたコードをGitHub Actionsのスケジュール機能を使って動かしています。 このbotを作成する上でApp Store Connect APIからデータを取得し新規DL数を出力する、Go言語のライブラリであるgoisumobilereportを作成しました。

この記事では、goisumobilereportを使って、どのように新規DL数を取得するか簡単にですが、ご紹介したいと思います!(以前書いた記事の増強版です)

  1. 準備
  2. 新規DL数を取得
  3. APIにリクエストを送る
  4. どうやって判別しているか
  5. 最後に

準備

App Store Connect APIでは、JWTを使った認証が必要です。そのために、APIキーを準備する必要があります。 App Store Connectのダッシュボードにアクセスし、「ユーザとアクセス」 → 「キー」 を選択し、「+ボタン」 をクリックして、APIキーを生成して下さい。この時、アクセスはFinanceを選択して下さい。発行したAPIキーは一度しかダウンロードできないので大事に保管して下さい。 次に、Issuer IDを準備します。Issuer IDは、「ユーザとアクセス」 → 「キー」の箇所に書いてあります。 Issuer IDの場所

新規DL数を取得

新規DL数の情報を取得するエンドポイントは、https://api.appstoreconnect.apple.com/v1/salesReportsになります。ドキュメントはこちらです。このエンドポイントは、自分のチームの全iOSアプリのDL数やアップデート数などが載っているgzipにされたtsv形式のファイルが取得できます。 tsvファイルに載っている中身は、DAILYWEEKLYMONTHLYYEARLYの4つが選択できます。 レポートの配信タイミングは、こちらに書いてあります。

WEEKLYのデータを取るときは注意が必要で、週の日曜日の日付を指定する必要があります。取得するタイミングも注意が必要で時差を考慮する必要があります。具体的には、日本標準時(JST)と、太平洋標準時(PST)では、17時間の時差があります。これに加え、レポートの配信タイミングがPSTの午前8時までに配信されます。この点に注意をする必要があります。

APIにリクエストを送る

JWTを作成してAPIにリクエストを送ります。ドキュメントはこちらです。最初は、Google Apps Script(GAS)で定期実行しようと思ったのですが、App Store Connect APIのJWTでは、ES256というアルゴリズムが使われており、これを扱うためのライブラリをGAS上で見つけることが出来なかったので、Go言語で実装しました。

JWT認証と新規DL数の取得の箇所はgoisumobilereportという名前のGo言語のライブラリを作成したので、そちらを使っていきます。 このライブラリでは、JWTの準備から、新規DL数などが載っているgzipにされたtsvファイルを取得、解凍し、新規DL数などのデータを出力できます。

まずは、ライブラリを手元に持ってきます。

go mod init github.com/Tatsumi0000/AppStoreConnectNewDL
go get github.com/Tatsumi0000/goisumobilereport

サンプルとして2021-03-23(PST)の日次レポートをApp Store Connect APIから取得後、機種別の新規DL数を表示するコードを紹介します。 各処理と必要なパラメータに関しては、コメントとして書いています。

package main

import (
	"fmt"
	"io/ioutil"

	goisu "github.com/Tatsumi0000/goisumobilereport/goisumobilereport"
)

func main() {
	const (
		// Issuer ID
		issUserID = "ISSUER_ID"
		// 生成したキーID
		keyID = "KEY_ID"
		// App Store Connectで生成したファイル
		p8Filepath = "./XXXXXX.p8"
		// App Store Connect APIで取得したtsvファイルを保存するパス
		filepath = "./salesReport.tsv"
	)
	// p8の中身を読み込む
	p8, _ := ioutil.ReadFile(p8Filepath)
	// JWTの準備
	app, _ := goisu.NewAppStoreConnectAPIJwt(issUserID, keyID, p8)

	// VENDOR_IDにチームのベンダーIDを入れて下さい。
	// 2021年03月23日のレポートを取得
	app.StoreConnectAPIRequest("SALES", "SUMMARY", "DAILY", "1_0", "VENDOR_ID", "2021-03-23", filepath)

	// tsvファイルをパースしてSlicesのポインタを返す
	contents, _ := goisu.ParseTsvFile(filepath)

	// SKUの箇所に取得したいアプリのSKUを入れて下さい。
	// 新規DLした機種と回数のmapポインタと、合計新規DL数を返す
	newInstallCounts, newInstallSumCounts := goisu.NumberOfNewDownloads(contents, "SKU")

	for key, value := range *newInstallCounts {
		fmt.Printf("%v: %v回\n", key, value)
	}
	fmt.Printf("合計新規インストール数: %v回\n", newInstallSumCounts)
}

(エラー処理は省略しています。)

作成したライブラリでは再DL数や国別のDL数をパースする関数も入っています。

どうやって判別しているか

App Store Connect APIから取得したtsvファイルの中身はいろいろなデータが入っています。新規DLかどうかを判断するために、Product Type Identifierで判断し、Unitsの数をDL数として数えています。新規DLのProduct Type Identifierは、1がついているものを新規DLとしてカウントしています。再DLは、3がついているものをカウントしています。これらの判断に関しては、iTunes Connectの売上とトレンドを自動取得するNew Product Type Identifier - 3F? in App Sales Reportを参考にさせていただきました。

最後に

作成したコードは、GitHub Actionsのスケジュール機能で動いています。 レポートから取得したデータを、Slackに投稿後、iOSアプリ別にGoogle Spread Sheetにデータを毎日記録するようにしています。 実際に動いている様子がこちらです。 実際にSlackに投稿しているbot

先日、Google Spread Sheet上に集めたデータを、Data Studioでグラフ化してもらい、より見やすくなりました。 以下のような形で表示しています。(以下の画像はイメージ図で、実際のDL数とは違います) SpreadSheetのデータをグラフ化したイメージ図

これらのデータを定例会で共有し、○○をした後は新規DL数が伸びました!といった話をみんなでわいわいしています。

簡単ではありますが、App Store Connect APIからiOSアプリの新規DL数を取得する方法について紹介しました。 初めてライブラリを作ったのですが、どうすればいいのか悩みながら作りました。もともとはライブラリ化する予定もなく、main.goの中に全部書いていました。コードを書いていくうちにどうせだったらOSSとして公開しようと思い、コードの分割を始めました。 予めコードを分割することを意識して書いていなかったので、後から見直すと微妙な箇所がありました。例えば、goisumobilereportの中には、appStoreConnectApiJWT.goがあるのですが、この中にgzipファイルを解凍するコードがあります。ファイル名と、書いてあるコードに齟齬があるので新しくファイルを作って、そこに移したほうがいいなと思いました。しかし、使っているのはこのファイルの中身だけなので、そこまで厳密にしなくてもいいのかなとも思っていて、自分の中でまだ答えが出ていません。

どのようなコードを書くと扱いやすいのか第三者視点の目線を持って、きれいなコードを書けるようなエンジニアになれるように頑張りたいと思います!