はじめに
Admobの収益を毎日確認したいのですが、毎回PCを開くのは面倒です。そんな時Slackでスマホに通知がくるシステムがあると便利そうです。調べてみると、Admobのデータが取得できるAdmob APIがあるようなので、そのAPIを使って収益データを毎日Slackで通知するシステムを作成しました。最終的にこのようなレポートがSlackに毎日届くことを目指します。
この記事では、システムの構築方法やその際の注意点等をまとめています。
アーキテクチャ全体
まず大まかな処理の流れを説明します。
- 毎朝Apps Scriptが定期実行される
- Apps ScriptでAdmob APIを呼ぶ
- Apps ScriptでAdmob APIのレスポンスから広告のタイトルと金額を抽出し、Slackで送りたいメッセージを作成
- Apps ScriptでSlack APIにそのメッセージを送信
※Admob APIはOAuthで認可するため初回のみ一度認可処理が必要ですが、2回目以降は以上の処理を繰り返します。
Admob API
初期設定
まずは公式のドキュメント通りに「プロジェクトを作成する」の設定を行ってください。
動作確認
続いてドキュメント通りに「リクエストを作成する」の通りに簡単にshellで動作確認を行ってください。とりあえず「2. アカウント情報を取得します。」までできたら、設定完了です。実際使いたいのは、「3. ネットワーク レポートを生成する。」で使用しているエンドポイントですが、実はこのコマンドは間違っています。ほんの少しのOAuthの知識とLinuxの知識があれば気づけるはずですが、私は少し時間がかかってしまいました。。
誤
-H "$(oauth2l header --json path_to_credentials_json \
正
-H "$(oauth2l header --json path_to_credentials_json \
https://www.googleapis.com/auth/admob.readonly)"
リクエスト作成
今回のシステムで実際に取得したい情報は、ある期間での広告ユニット毎の推定収益額です。そのため、エンドポイント「v1/accounts/pub-XXXXXXXXXXXXXXXX/networkReport:generate」にリスクエストを送ります。これがそのエンドポイントのリファレンスです。
(https://developers.google.com/admob/api/v1/reference/rest/v1/accounts.networkReport/generate)
画面右側のペインをポチポチしてRequest bodyを作成します。ディメンションの値等は、このリファレンス(https://developers.google.com/admob/api/v1/report-metrics-dimensions)を見て決めます。今回はディメンションにAD_UNIT、メトリクスにESTIMATED_EARNINGSを使用します。
完成したリクエストをcURLで表すと以下のようになります。この後これをApps Scriptで書き直します。
curl -X POST \
https://admob.googleapis.com/v1/accounts/pub-XXXXXXXXXXXXXXXX/networkReport:generate \
-H "$(oauth2l header --json path_to_credentials_json \
https://www.googleapis.com/auth/admob.readonly)"
-H "Content-Type: application/json" \
--data @- << EOF
{
"report_spec": {
"date_range": {
"start_date": {"year": 2022, "month": 5, "day": 1},
"end_date": {"year": 2022, "month": 5, "day": 1}
},
"dimensions": ["AD_UNIT"],
"metrics": ["ESTIMATED_EARNINGS"]
}
}
EOF
Slack API
ここはたくさん記事があるので詳しい説明は割愛します。こういった記事が参考になります。(https://zenn.dev/kou_pg_0131/articles/slack-api-post-message)最終的にAdmobのレポート通知用のチャンネルと、「Bot User OAuth Token」を作成できていればOKです。
Apps Script
Apps Scriptは、次のフローを実装していきます。
- Admob APIからデータ取得
- Slack通知用のメッセージを作成
- Slack APIへ送信
細かい部分は、コード内のコメントを参照いただければと思います。
OAuth周りの処理はライブラリのREADMEを読んでサンプルを改造した形になります。
デプロイ手順
- 新しいスプレッドシートを作成し[拡張機能]>[Apps Script]をクリックし、以下のコードを貼り付けてください。
const Properties = PropertiesService.getScriptProperties();
const admobAPIService = getAdmobAPIService();
// OAuthの準備
function getAdmobAPIService() {
return OAuth2.createService("AdmobAPI")
.setAuthorizationBaseUrl("https://accounts.google.com/o/oauth2/auth")
.setTokenUrl("https://oauth2.googleapis.com/token")
.setClientId(Properties.getProperty("ADMOB_CLIENT_ID"))
.setClientSecret(Properties.getProperty("ADMOB_CLIENT_SECRET"))
.setCallbackFunction("authCallback")
.setPropertyStore(PropertiesService.getUserProperties())
.setScope("https://www.googleapis.com/auth/admob.readonly")
.setParam("access_type", "offline")
.setParam('prompt', 'consent');
}
// 認証処理後のコールバックの処理を定義
function authCallback(request) {
const isAuthorized = admobAPIService.handleCallback(request);
if (isAuthorized) {
return HtmlService.createHtmlOutput("認可処理が正常に終了しました。このタブを閉じてください。");
} else {
return HtmlService.createHtmlOutput("認可処理に失敗し、リソースへのアクセスが拒否されました。設定を確認してください。");
}
}
// スプレッドシートのメニューにAdmob API認可用のボタンを設置
function onOpen() {
SpreadsheetApp.getUi()
.createMenu("Admob API連携")
.addItem("認可処理", "initAuth")
.addToUi();
}
// Admob API認可URLをダイアログに表示
function initAuth() {
const authorizationUrl = admobAPIService.getAuthorizationUrl();
const template = HtmlService.createTemplate(
'<a href="<?= authorizationUrl ?>" target="_blank">認可</a>. Admob APIの認可をします。'
);
template.authorizationUrl = authorizationUrl;
const page = template.evaluate();
const title = "Admobアプリの認可処理";
createModelessDialog(page, title);
}
// ダイアログを表示
function createModelessDialog(html, title) {
const htmlOutput = HtmlService.createHtmlOutput(html)
.setWidth(360)
.setHeight(120);
SpreadsheetApp.getUi().showModelessDialog(htmlOutput, title);
}
// ある期間(startDate ~ endDate)の広告ユニットごとの推定収益をAdmob APIから取得
function getAdmobReport(startDate, endDate) {
const payload = JSON.stringify({
"report_spec": {
"date_range": {
"start_date": startDate,
"end_date": endDate
},
"dimensions": ["AD_UNIT"],
"metrics": ["ESTIMATED_EARNINGS"]
}
});
const response = UrlFetchApp.fetch(
"https://admob.googleapis.com/v1/accounts/pub-2781004360728551/networkReport:generate",
{
headers: {
Authorization: "Bearer " + admobAPIService.getAccessToken(),
},
contentType: "Content-Type: application/json",
payload: payload
}
);
return JSON.parse(response);
}
// 昨日の日付をオブジェクトで返す。
function getYesterdayDate() {
const objDate = new Date();
objDate.setDate(objDate.getDate() - 1);
return {
year: objDate.getFullYear(),
month: objDate.getMonth() + 1,
day: objDate.getDate()
}
}
// Admob APIのレスポンス(json)をもとに、広告ユニット毎の推定収益のレポートを作成する。
// 日付がundefinedのときは月単位のレポート作成する。
function makeReportMessage(json, year, month, day) {
let message = `${year}年${month}月${day ? `${day}日` : ''}のAdmob推定収益レポートです。
\`\`\`
`;
let toalEarnings = 0;
for (let i = 1; i < json.length - 1; i++) {
toalEarnings += Number(json[i].row.metricValues.ESTIMATED_EARNINGS.microsValue);
// Math.trunc(NUMBER).toLocaleString().padStart(6, " ");
// ↑この処理はNUMBERの小数点以下切り捨てて、3桁ごとにカンマを入れつつ文字列に変換し、6文字を最大値として右揃えにする。
// 例1) 1234.56 → " 1,234"
// 例2) 123.456 → " 123"
message += `${json[i].row.dimensionValues.AD_UNIT.displayLabel}:
${Math.trunc(json[i].row.metricValues.ESTIMATED_EARNINGS.microsValue / 1000 / 1000).toLocaleString().padStart(6, " ")}円
`;
}
message += `---
合計:
${Math.trunc(toalEarnings / 1000 / 1000).toLocaleString().padStart(6, " ")}円
\`\`\``;
return message;
}
// メッセージ(message)をSlackの特定のチャンネル(channel)へ送信する。
function postToSlack(channel, message) {
const url = "https://slack.com/api/chat.postMessage";
const token = Properties.getProperty("SLACKBOT_TOKEN");
const options = {
"method": "post",
"contentType": "application/x-www-form-urlencoded",
"payload": {
"token": token,
"channel": channel,
"text": message
}
};
UrlFetchApp.fetch(url, options);
}
// エントリーポイント
function main() {
// トークンがなければ認可処理を促す
if (!admobAPIService.hasAccess()) {
let message = "トークンの期限が切れました。スプレッドシートを開いて再認証してください。";
console.log(message);
// Slack APIへメッセージを送信
postToSlack("#admob-report", message);
return;
}
// この変数messageにSlackに通知するメッセージを追加していく
let message = '<!channel>\n';
// 昨日の収益レポートを作成する
const { year, month, day } = getYesterdayDate();
const yesterdayResponse = getAdmobReport(
{ year, month, day },
{ year, month, day },
);
message += makeReportMessage(yesterdayResponse, year, month, day);
// 体裁を整えるため改行
message += "\n\n";
// 今月の収益レポートを作成する
const thisMonthResponse = getAdmobReport(
{ year, month, "day": 1 },
{ year, month, day },
);
message += makeReportMessage(thisMonthResponse, year, month);
console.log(message);
// Slack APIへメッセージを送信
postToSlack("#admob-report", message);
}
- 権限を追加
- 左側歯車アイコンの[プロジェクトの設定]をクリック [全般設定] > [「appsscript.json」マニフェスト ファイルをエディタで表示する] をクリック
- 左側のボタン[エディタ]をクリックし戻ると、appsscript.jsonが表示されている。
- appsscript.json以下のコードを追加
{
// …
"oauthScopes": [
"https://www.googleapis.com/auth/script.external_request",
"https://www.googleapis.com/auth/script.container.ui",
"https://www.googleapis.com/auth/spreadsheets"
],
// …
}
- ライブラリ(OAuth2 for Apps Script)を追加
- こちらのSetupを行う
- スクリプト プロパティ(環境変数)の追加
- AdmobのClientIdをADMOB_CLIENT_IDという名前で保存
- AdmobのClientSecretをADMOB_CLIENT_SECRETという名前で保存
- SlackのBot User OAuth TokenをSLACKBOT_TOKENという名前で保存
- Admob APIをApps Scriptから利用可能にするよう認可処理を行う。
- ファイルを保存し、スプレッドシートをリロードする。
- 新たに追加されているメニュー [Admob API連携] > [認可処理]をクリック
- ダイアログ内の認可リンクをクリックし認可する。
このときAdmob APIで許可したGoogleアカウントでログインし認可処理を行ってください。
- テスト実行
- Apps Scriptに戻って、main関数を実行
- 定期実行
- 左側目覚まし時計 トリガーをクリック
- 右下[トリガーを追加]をクリック
- 画像の通りに設定
まとめ
Admob APIを用いてSlackに収益の簡易レポートを定期送信するシステムの構築方法を紹介しました。Admob APIから取得したデータを用いて、グラフを作成しても良いかと思いましたが、Slackの容量を圧迫しそうであることと、時間がかかりそうであるため今回は文字列のみのレポートにしています。ただ実際グラフが必要なときは、リッチなDashboardサービスを使ったほうが良いかもしれないですね!