[Qiita] GASを使ってAndroidアプリのインストール数を自動で取得してスプレッドシートに入れる

※この記事は以前Qiitaに投稿されていた古い記事です

はじめに

Androidアプリのインストール数を取得したいという要望があり、Google Apps Scriptなら手軽に書けてスプレッドシートにもサクッと挿入できるのでは…?と思ってやってみたらできたので、メモとして書いておきます。
基本コピペをすればできるように書いたつもりなので、GASの知識がなくても自動で取得するようにできる…はず。

流れ

画像多めですごく長いので、大まかにやることの流れだけ書いておきます

  1. GASでGoogle Cloud Storageにアクセスできるように認証情報を作成する
  2. 認証情報を使ってGCSからレポートを取得するのに必要なAccessTokenを取得するスクリプトを書く(コピペ)
  3. 自動実行できるようにRefreshTokenをつかってAccessTokenを取得するスクリプトを書く(コピペ)
  4. Google Play Developer ConsoleでインストールレポートのURIをメモる
  5. Androidアプリのインストール数を取得してスプレッドシートに挿入するスクリプトを書く(ほぼコピペ)
  6. スクリプトを実行する
  7. 定期実行する設定を行う

Google API ConsoleでAPIを有効にする

Google PlayのインストールレポートはGoogle Cloud Storageの中に入っているので、それをダウンロードできるようにGoogle Cloud Storage JSON APIを有効にしておく
スクリーンショット 2016-06-27 17.25.53.png

Google API Consoleで認証情報を作成する

クライアントIDとクライアント シークレット

  1. 認証情報を作成ボタンを押して、「OAuth クライアント ID」を選択
    スクリーンショット 2016-06-27 16.37.59.png

  2. 名前は適当に決めて、「承認済みのリダイレクトURI」のところにはGoogle Apps ScriptのURLのmacros/d/から/editの間にあるKey的なやつを取り出して以下の様なURLにして入れておく
    (下で説明してるスクリプトエディタを開いたときのURLから取り出す)

https://script.google.com/macros/d/<<--Key的なやつ-->>/usercallback

スクリーンショット 2016-06-27 16.45.08.png
3. 作成してできたクライアントIDとクライアント シークレットをどこかにメモしておく
スクリーンショット 2016-06-27 17.35.14.png

認証情報をスクリプトプロパティにセットする

  1. スクリプトエディタを開く
    スクリーンショット 2016-06-27 17.03.52.png

  2. プロジェクトのプロパティを開く
    スクリーンショット 2016-06-27 17.01.49.png

  3. スクリプトのプロパティタブを開いて、「行を追加」からclientIdとclientSecretを追加して「保存」ボタンを押す
    スクリーンショット 2016-06-27 17.08.32.png

これで準備はOK

AccessTokenを取得する

  1. スクリプトの名前を分かりやすいように変えておく
    スクリーンショット 2016-06-27 19.25.13.png

スクリーンショット 2016-06-27 19.25.38.png

  1. AccessTokenの取得スクリプトを書く(コピペでOK)
var prop = PropertiesService.getScriptProperties()
var clientId = prop.getProperty("clientId");
var clientSecret = prop.getProperty("clientSecret");
var redirect_uri = "https://script.google.com/macros/d/<<--Key的なやつ-->>/usercallback";

function startOAuth(){
    var url = 'https://accounts.google.com/o/oauth2/auth?client_id=' + clientId;
    url += '&redirect_uri=' + encodeURIComponent(redirect_uri);
    url += '&scope=' + encodeURIComponent("https://www.googleapis.com/auth/devstorage.read_only");
    url += '&state=' + ScriptApp.newStateToken().withMethod('callback').withArgument('name', 'value').withTimeout(2000).createToken();
    url += '&response_type=code';
    url += '&approval_prompt=force';
    url += '&access_type=offline';
  
    var template = HtmlService.createTemplate('<center><a href="<?= AUTH_URL ?>" target="_blank">認証開始</a>. </center>' + 
                                              '<center>認証完了したらタブを閉じて再度実行してください</center>');
    template.AUTH_URL = url;
    var page = template.evaluate();
    // 認証URLへ飛ばす
    SpreadsheetApp.getUi().showModalDialog(page, "Google API認証");
}

function callback(e){
  Logger.log(e.parameter.code);
  var params = {
    "method" : "POST",
    "payload" : {
      "code" : e.parameter.code,
      "client_id" : clientId,
      "client_secret" : clientSecret,
      "redirect_uri" : redirect_uri,
      "grant_type" : "authorization_code"
    },
    "muteHttpExceptions" : true
  };
  var res = UrlFetchApp.fetch('https://accounts.google.com/o/oauth2/token', params);
  var dat = JSON.parse(res.getContentText());
  var access_token = dat.access_token;
  var refresh_token = dat.refresh_token;
  
  prop.setProperty('access_token', access_token);
  prop.setProperty('refresh_token', refresh_token);
}

実行してみる

  1. 実行メニューからstartOAuthを選んで実行
    スクリーンショット 2016-06-27 17.38.40.png

  2. 許可を求められるので許可する
    スクリーンショット 2016-06-27 17.38.49.png

  3. また許可を求められるので許可する 
    スクリーンショット 2016-06-27 17.39.00.png

  4. スプレッドシート側にこんな画面がでてくるので認証開始を押す
    スクリーンショット 2016-06-27 17.40.06.png

  5. また許可を求められるので許可する
    スクリーンショット 2016-06-27 17.40.21.png

  6. 何も返してないので何も出てきませんが、こんな感じの画面が出てきたら完了
    スクリーンショット 2016-06-27 17.40.38.png

  7. スクリプトのログを確認
    スクリーンショット 2016-06-27 17.40.55.png

  8. こんな感じでAccessTokenっぽいものが出てきてたらOK
    スクリーンショット 2016-06-27 17.41.05.png

  9. また、スクリプトのプロパティにaccess_tokenとrefresh_tokenが入っていればOK
    スクリーンショット 2016-06-27 17.41.28.png

RefreshTokenを使ってAccessTokenを取得する

AccessTokenには期限があるため、上記の認証方法では、しばらくするとまた認証許可を行わなければならないため、定期的に自動で取得することができません。
そこで、認証時に取得したRefreshTokenを使ってAccessTokenを取得することで、毎回新しいAccessTokenを取得できるようにします。(コピペでOK。上記のスクリプトに追記する)

function getAccessToken() {
  if (prop.getProperty("access_token") == null) {
    startOAuth();
    return;
  }
  
  var payload;  
  if (prop.getProperty("refresh_token") != null) {
    payload = {
      "client_id" : clientId,
      "client_secret" : clientSecret,
      "redirect_uri" : redirect_uri,
      "grant_type" : "refresh_token",
      "refresh_token" : prop.getProperty("refresh_token")
    };
  } else {
    return null;
  }
    
  var params = {
    "method" : "POST",
    "payload" : payload,
    "muteHttpExceptions" : true
  };
  var res = UrlFetchApp.fetch('https://accounts.google.com/o/oauth2/token', params);
  var dat = JSON.parse(res.getContentText());
  var access_token = dat.access_token;
  prop.setProperty('access_token', access_token);
  Logger.log(access_token);
  return access_token;
}

というわけで実行してみる

  1. getAccessTokenを実行
    スクリーンショット 2016-06-27 17.55.48.png
  2. ログを見て、無事に取得できてればOK
    スクリーンショット 2016-06-27 17.56.31.png

Google Play Developer ConsoleでレポートのURIを確認する

  1. GPDCの統計情報からアプリを選ぶ
    スクリーンショット 2016-06-27 20.11.16.png

  2. 下の方にあるレポートの直接URIの/stats/installsと書いてあるやつの黒で隠してある部分の数字をメモる
    スクリーンショット 2016-06-27 20.16.05.png

Androidアプリのインストール数を取得してスプレッドシートに挿入する

前準備

  1. 元データという名前のシートを作る
    (名前は何でもいいけどスクリプトの中に書いちゃったので)
  2. 一番上にカラム名と、dateの部分に日付を入れておく
    (スプレッドシートに記載してある日付を元にその行に値を入れるので、日付入ってないと動きません)
    スクリーンショット 2016-06-27 20.51.14.png

スクリプトファイルを2つ作る

メニューからスクリプトファイルを選んで、
スクリーンショット 2016-06-27 20.54.34.png

  1. Utils
    スクリーンショット 2016-06-27 21.07.43.png

  2. AndroidAppReport
    スクリーンショット 2016-06-27 21.08.00.png

を作成する

Utils.gsに以下をコピペ

var SPREADSHEET = SpreadsheetApp.openById("ここにスプレッドシートのKeyを記入");

/** スプレッドシートを取得 */
function getSheetByName(sheetName) {
  return SPREADSHEET.getSheetByName(sheetName);
}

// スプレッドシートに値を入れる
function setValueToSpreadsheet(sheetName, arrayValue, rowCount, columnCount) {
  // スプレッドシートを取得
  var sheet = getSheetByName(sheetName);
  // シートに書き込む
  sheet.getRange(rowCount, columnCount, arrayValue.length, arrayValue[0].length).setValues(arrayValue);
}

/** 今月の行の位置を取得する */
function getThisMonthRow(offset) {
  if(!hasSheet("tmp")) {
    SPREADSHEET.insertSheet("tmp");
  }
  var sheet = SPREADSHEET.getSheetByName("tmp");
  var date = getDate(offset);
  var r = sheet.getRange(1, 1).setFormula("MATCH(DATE("+Utilities.formatDate(date, "JST", "yyyy,MM,01")+"),元データ!B:B,0)");
  var reply = sheet.getDataRange().getValues();
  SPREADSHEET.deleteSheet(sheet);
  
  return reply;
}

/** 年月を取得 */
function getFormatDateString(isSlash, offSet) {
  var myDate = new Date();
  var dayOfMonth = myDate.getDate();
  myDate.setDate(dayOfMonth + offSet);
  if (isSlash) {
    return Utilities.formatDate(myDate, "JST", "yyyy/MM");
  }
  return Utilities.formatDate(myDate, "JST", "yyyyMM");
}

/** 日付を取得する */
function getDate(offSet) {
  var myDate = new Date();
  var dayOfMonth = myDate.getDate();
  myDate.setDate(dayOfMonth + offSet);
  return myDate;
}

/** シートが存在するかどうか */
function hasSheet(sheetName) {
  var sheet = getSheetByName(sheetName);
  if (sheet == null) {
    return false;
  }
  return true;
}

/** 正規表現でセパレート */
function separate(num){
    return String(num).replace( /(\d)(?=(\d\d\d)+(?!\d))/g, '$1,');
}

/** Google Cloud Storageからファイルを取得する */
function getFromGcs(url) {
  var token = getAccessToken();
  var response = UrlFetchApp.fetch(url, {
    muteHttpExceptions:true,
    headers: {
     "Authorization": "Bearer " + token,
    },
    method: "GET"
  });
  return response.getContentText();
}

/** 余計な文字を除外して取得 */
function fixedString(str, package_name) {
  var fixed_str = "";
  for (var i = 0; i < str.length; ++i) {
    if (str.charCodeAt(i) != 0 && str.charCodeAt(i) != 65533) {
      fixed_str += str[i];
    }
  }
  fixed_str = fixed_str.replace(new RegExp(package_name, 'g'), "");
  return fixed_str;
}

一番上の、ここにスプレッドシートのKeyを記入と書いてある部分に以下のここと書いてある部分をコピーして貼り付けておく
https://docs.google.com/spreadsheets/d/ここ/edit

AndroidAppReport.gsに以下をコピペ

レポートのURIを確認したときにメモった数字を、一番上の部分に記入し、ここにアプリのパッケージ名を記入と書いてある部分に、レポートを取得したいアプリのパッケージ名を記入する。

var bucket_id = "ここにレポートのURIを確認したときの数字を記入";

function main() {
  getInstalls("ここにアプリのパッケージ名を記入");
}

function getInstalls(package_name) {
  // URLを作成する
  var object_url = "https://www.googleapis.com/storage/v1/b/pubsite_prod_rev_" + bucket_id + "/o/stats%2Finstalls%2Finstalls_" + package_name + "_" + getFormatDateString(false, -3) + "_overview.csv";
  // Google Cloud Storageからファイルの情報を取得する
  var data = getFromGcs(object_url);
  // jsonをparseする
  var obj_meta_data = JSON.parse(data);

  // 実際のデータが入ってるURLからcsvを取得してくる 
  data = getFromGcs(obj_meta_data.mediaLink);
  // 余計な文字列を削除する
  var fixed_data = fixedString(data, package_name);
  // csvをparseする
  var csv_data = Utilities.parseCsv(fixed_data);
  // 一番上の行を消す
  csv_data.shift();
  // 今月最初の日付の位置を取得する(今日が2016/06/27なら2016/06/01の位置が返ってくる)
  var this_month_row = getThisMonthRow(-3);
  if (this_month_row > 0) {
    // スプレッドシートにデータを挿入する
    setValueToSpreadsheet("元データ", csv_data, this_month_row, 2);
  }
}

実行する

AndroidAppReport.gsを開いて、上のメニューからmainを実行する。
スクリーンショット 2016-06-27 21.19.02.png

許可を求められるので、許可する
スクリーンショット 2016-06-27 20.56.03.png

スプレッドシートへのアクセス許可を求められるので、許可する
スクリーンショット 2016-06-27 20.56.15.png

エラーが出なければ無事に実行完了しているはずなので、スプレッドシートを確認する

スクリーンショット 2016-06-27 21.24.46.png

できた!

インストール数の取得を定期的に実行させる

Google Apps Scriptではトリガーというものをセットして任意の処理を定期的に実行させることができるので、それを利用してインストール数を自動で取得できるようにする

  1. このボタンを押す
    スクリーンショット 2016-06-27 21.40.55.png
  2. こんな感じで設定して保存ボタンを押す
    スクリーンショット 2016-06-27 21.41.27.png

これで毎日7時くらいにスプレッドシートに自動で値が挿入されるようになります。
エラーが発生したときに通知させたいときは「通知」ボタンからその設定もすることができます。
すばらしい!

おまけ

Chatworkに通知できるようにする

弊社ではChatworkを使っているので、Chatworkにも最新の数値を自動で通知するようにしてみました。
これがChatworkにpostするfunction。

var API_KEY = "ここにAPIKeyを記入";

function chatworkPost(room_id, message) {
  var options = {
    method: 'post',
    headers: {
      "X-ChatWorkToken": API_KEY,
    },
    payload: {
      "body": message
    }
  };
  var response = UrlFetchApp.fetch("https://api.chatwork.com/v1/rooms/" + room_id + "/messages", options);
  return response;
}

あとは下記のスクリプトをgetInstallsの一番下に追記するだけでOK

function getInstalls(package_name) {

  /** 省略 */

  var date = csv_data[csv_data.length -1][0].split("-");
  var format_date = date[0] + "年" + date[1] + "月" + date[2] + "日";
  var str = "[info][title]";
  str += format_date + " のAndroidアプリインストールレポート[/title]";
  str += "【端末】現在のインストール数\t\t\t\t: "       + separate(csv_data[csv_data.length -1][2]) + "\n";
  str += "【端末】デイリーインストール数\t\t\t\t: "      + separate(csv_data[csv_data.length -1][3]) + "\n";
  str += "【端末】デイリーアンインストール数\t\t\t: "     + separate(csv_data[csv_data.length -1][4]) + "\n";
  str += "【端末】デイリーアップグレード数\t\t\t: "       + separate(csv_data[csv_data.length -1][5]) + "\n";
  str += "【ユーザー】現在のインストール数\t\t\t: "      + separate(csv_data[csv_data.length -1][6]) + "\n";
  str += "【ユーザー】デイリーインストール数\t\t\t: "     + separate(csv_data[csv_data.length -1][8]) + "\n";
  str += "【ユーザー】デイリーアンインストール数\t\t: "    + separate(csv_data[csv_data.length -1][9]) + "\n";
  str += "【ユーザー】合計インストール数\t\t\t\t: "      + separate(csv_data[csv_data.length -1][7]) + "[/info]";
  chatworkPost(ROOM_ID, str);
}

おわりに

自動取得できるcsvファイルは3日ほど遅れているので、常に最新値を取得できるわけではないですが、スプレッドシートに値があれば色々なことができると思うので、ぜひ使ってみてはいかがでしょうか。
以上、おつかれさまでした。

参考



コメント

人気の投稿

【Linux】Linuxでディレクトリ毎にzip圧縮する

[Qiita] Google Playのクローズドベータ版テストでメールアドレスを指定して公開する

[Qiita] Androidの実機でPCのlocalhostに接続したり、Webページの要素を検証する