C#からAndroid(Google Play Console)の実績を登録する

Google Play Consoleでの実績の登録って、実績数 * 言語数の作業が発生するのでとても手作業でやってられません。
ということで、C#からやりましょう。

Google Play Games Services Publishing APIのセットアップ

Google Play Games Services Publishing API スタートガイドの通りに、ApplicationIdとサービスアカウント(の認証情報が入ったjsonファイル)を準備します。
このApplicationId、なんと Google Play Console上でのアプリケーションのID ではなく Google Play Game Servicesに紐づいたGoogle Cloud PlatformのプロジェクトID (数字)です。
自分はこれで数時間潰しました。

取得する

あとはAPIリファレンス通りに叩くだけです。
まずはこんな感じにConfigurableHttpClientを作ってやって、

private static ConfigurableHttpClient CreateHttpClient()
{
    var scopes = new[]
    {
        "https://www.googleapis.com/auth/androidpublisher"
    };

    // JsonfilePathはサービスアカウントの認証情報が入ってる落としてきたjsonファイルへのパス
    var stream = new FileStream(JsonfilePath, FileMode.Open, FileAccess.Read);
    var credential = (ServiceAccountCredential) GoogleCredential.FromStream(stream)
        .CreateScoped(scopes)
        .UnderlyingCredential;

    var initializer = new BaseClientService.Initializer
    {
        HttpClientInitializer = credential,
        ApplicationName = "DotnetScripts",
    };

    var factory = initializer.HttpClientFactory;
    var args = new CreateHttpClientArgs
    {
        GZipEnabled = false,
        ApplicationName = initializer.ApplicationName,
    };
    if (initializer.HttpClientInitializer != null)
    {
        args.Initializers.Add(initializer.HttpClientInitializer);
    }

    var httpClient = factory.CreateHttpClient(args);
    if (initializer.MaxUrlLength > 0)
    {
        httpClient.MessageHandler.AddExecuteInterceptor(new MaxUrlLengthInterceptor(initializer.MaxUrlLength));
    }
    return httpClient;
}

認証さえ通ってしまえばあとはかんたん

var httpClient = CreateHttpClient();
var request = await httpClient.GetAsync($"https://www.googleapis.com/games/v1configuration/applications/{ApplicationId}/achievements");
var resultString = await request.Content.ReadAsStringAsync();

jsonで落ちてくるので、Newtonsoft.Jsonを使って欲しいところだけファイルに保存。

var deserializeObject = JObject.Parse(resultString);
var jsonString = JsonConvert.SerializeObject(deserializeObject["items"], Formatting.Indented);
await File.WriteAllTextAsync(path, jsonString, Encoding.UTF8);

登録する

上記の方法で保存したjsonをよしなにいじったら、改めて登録し直します。
取得は一気にできますが、更新は1つずつ。

var httpClient = CreateHttpClient();
var jArray = JArray.Parse(await File.ReadAllTextAsync(path, Encoding.UTF8));
foreach (var (element, i) in jArray.Select((x, i) => (x, i)))
{
    var achievementId = element["id"]!.Value<string>()!;
    var content = JsonConvert.SerializeObject(element, Formatting.None);
    Console.WriteLine($"{i + 1} / {jArray.Count} - {achievementId}");
    var request = await httpClient.PutAsync($"https://www.googleapis.com/games/v1configuration/achievements/{achievementId}", new StringContent(content, Encoding.UTF8));
    Console.WriteLine(request.StatusCode);
    if (!request.IsSuccessStatusCode) break;
}

余談

AppStoreConnectは iTMSTransporter を使って取得/登録ができます。