ZReviewTender — 無料オープンソースのアプリレビュー監視ロボット
リアルタイムでアプリの最新レビューを監視し、即座にフィードバックを提供することで、協力効率と顧客満足度を向上させます

ZhgChgLi / ZReviewTender

AppのレビューをSlackチャンネルへ
ZReviewTender — iOS/macOSのApp StoreおよびGoogle PlayのAndroidアプリの最新ユーザー評価を自動で監視し、継続的インテグレーションツールを提供してチームのワークフローに連携し、協力効率と顧客満足度を向上させます。
特徴機能
-
App Store iOS/macOS アプリと Google Play Android アプリのレビュー一覧を取得し、まだ取得していない最新のレビュー内容をフィルタリングする
-
[デフォルト機能] 取得した最新のレビューを Slack に転送し、メッセージのタイムスタンプリンクをクリックすると管理画面で素早く返信できます
-
[デフォルト機能] 指定した言語や地域以外のレビュー内容を Google Translate API を使って自動的に翻訳し、あなたの言語に対応します
-
[デフォルト機能] レビューを自動で Google Sheet に記録する機能をサポート
-
柔軟な拡張性をサポートしており、標準機能に加えてチームのワークフローに合わせて必要な機能を自分で開発し、ツールに統合できます。
例:評価を Discord、Line、Telegram などに転送する… -
タイムスタンプを使用してクロール位置を記録し、評価の重複クロールを防止する
-
フィルター機能をサポートし、特定の評価数、レビュー内容に含まれるキーワード、地域/言語のレビューのみを取得できます。
-
Apple は 新しい App Store Connect API を基に、安定かつ信頼できる App Store アプリのレビュー情報を提供しており、以前のように XML データが不安定だったり Fastlane Spaceship セッションが期限切れで定期的な手動メンテナンスが必要だった 状況とは異なります。
-
Android も公式の AndroidpublisherV3 API を使って評価データを取得します
-
GithubリポジトリとGithub Actionを使ったデプロイをサポートし、無料で迅速にZReviewTenderのAppレビュー監視ロボットを構築できます。
-
100% Ruby @ RubyGem
TL;DR [2024/09/27] アップデート
類似サービスとの比較

App Reviews ワークフロー統合例 (Pinkoi にて)
問題:

ショップの評価は製品にとって非常に重要ですが、それは非常に手作業で繰り返しの紹介やコミュニケーション作業です。
新しい評価を時々手動で確認し、カスタマーサポートの問題があればサポートに転送して対応してもらう必要があり、とても繰り返しで手間がかかります。

ZReviewTender 評価ロボットを使って、評価を自動的に Slack チャンネルに転送することで、皆が最新の評価情報を素早く受け取り、リアルタイムで追跡・議論できます。また、チーム全体が現在のユーザーの製品に対する評価や提案を把握できます。
詳細は以下をご参照ください: 2021 Pinkoi Tech Career Talk — 高効率エンジニアチームの秘密 。
デプロイ — デフォルト機能のみ使用
もし ZReviewTender のデフォルト機能(Slack/Google Translate/フィルター)だけを使いたい場合は、以下の簡単なデプロイ方法を利用できます。
ZReviewTender は RubyGems にて公開されており、RubyGems を使って簡単にインストールして利用できます。
[おすすめ] Githubリポジトリテンプレートを直接使ってデプロイする
-
サーバースペース不要 ✅
-
環境要件は一切不要 ✅
-
エンジニアリングの原理を理解する必要なし ✅
-
Config ファイルの設定が完了すれば、デプロイ完了 ✅
-
8つのステップでデプロイ完了 ✅
-
完全無料 ✅
Github Action はアカウントごとに月間 2,000 分以上の実行時間を提供し、ZReviewTender の評価取得は1回あたり約15〜30秒で完了します。
デフォルトでは6時間ごとに1回実行され、1日に4回実行します。1ヶ月あたり約60分の使用量です。
Github Private Repo は無料で無制限に作成可能です。
- ZReviewTender テンプレートリポジトリへ移動: ZReviewTender-deploy-with-github-action

右上の「Use this template」ボタンをクリックしてください。
- リポジトリの作成

-
Repository name: 入力したいリポジトリのプロジェクト名
-
アクセス: プライベート
⚠️⚠️ 必ず Private Repo を作成してください ⚠️⚠️
あなたが設定ファイルと秘密鍵をプロジェクトにアップロードするため
最後に下の「Create repository from template」ボタンをクリックしてください。
- 作成したリポジトリがプライベートリポジトリであることを確認する

右上のリポジトリ名に「🔒」と Private タグが表示されていることを確認してください。
もし設定していなければ、作成した Publicリポジトリは非常に危険 です。上部タブの「Settings」->「General」-> 下部の「Danger Zone」->「Change repository visibility」->「Make private」から Privateリポジトリに変更 してください。
- プロジェクトの初期化が成功するまで待つ
Repo ホームページの Readme にて記載可能です。

ブロックのバッジを確認し、passing であれば初期化が成功したことを意味します。
または上部のタブ「Actions」-> 「Init ZReviewTender」ワークフローの完了を待ちます:

実行完了状態は 3「✅ Init ZReviewTender」-> プロジェクト初期化成功になります。
- init ファイルとディレクトリが正しく作成されているか確認する

上部のタブ「Code」をクリックしてプロジェクトディレクトリに戻り、Project init が成功すると以下が表示されます:
-
目次:
config/ -
ファイル:
config/android.yml -
ファイル:
config/apple.yml -
目次:
latestCheckTimestamp/ -
ファイル:
latestCheckTimestamp/.keep
- Configuration の設定が完了し、
android.ymlとapple.ymlを準備する
config/ ディレクトリに移動し、android.yml と apple.yml ファイルの設定を完了してください。

編集する confi YML ファイルをクリックし、右上の「✏️」をクリックしてファイルを編集します。
本文下部の「 設定 」セクションを参照して、android.yml と apple.yml の設定を完了してください。

編集が完了したら、下の「Commit changes」から設定を保存できます。
対応するキー ファイルを config/ ディレクトリにアップロードしてください:

config/ ディレクトリ内で、右上の「Add file」->「Upload files」を選択してください。

config yml に設定した該当のキーや外部ファイルのパスをすべて config/ ディレクトリにアップロードし、ファイルを「上部ブロック」へドラッグ&ドロップします。アップロード完了を待ってから、下部の「Commit changes」をクリックして保存してください。
アップロード完了後、/config ディレクトリに戻り、ファイルが正しく保存およびアップロードされているか確認してください。

- ZReviewTender の初期化(手動で一度実行)

上部のタブ「Actions」をクリック -> 左側で「ZReviewTender」を選択 -> 右側のボタンから「Run workflow」を選択 -> 「Run workflow」ボタンをクリックして ZReviewTender を一度実行します。
クリックすると、ページをリロードします と表示されます:

「ZReviewTender」をクリックすると、実行状況を確認できます。

「 Run ZreviewTender -r 」ブロックを展開すると実行ログを確認できます。
ここでエラーが表示されていますが、まだ config yml ファイルを設定していないためです。
android/apple の config yml を調整した後、6. のステップの最初に戻って再度実行をトリガーしてください。

「 ZReviewTender -r 」ブロックのログを確認して、実行が成功したことを確認してください!

Slack の最新レビュー受信指定チャンネルにも init Success 成功メッセージが表示されます 🎉
- 完了! 🎉 🎉 🎉

設定完了!以降は6時間ごとに期間内の最新レビューを自動で取得し、あなたのSlackチャンネルに転送されます!
Repo のホームページの Readme のトップで最新の実行状況を確認できます:
![]()
エラーが発生した場合は、Actions → ZReviewTender からログを確認してください。予期しないエラーがある場合は、Issueを作成し、ログ情報を添付してください。できるだけ早く修正します!
❌❌❌実行中にエラーが発生すると同時に、GitHubからもメール通知が届くため、エラーでロボットが停止しても誰も気づかないという心配がありません!
Github Action の調整
ご自身のニーズに合わせて Github Action の実行ルールを設定することもできます。
上部のタブ「Actions」をクリック → 左側の「ZReviewTender」 → 右上の「 ZReviewTender.yml 」


右上の「✏️」をクリックしてファイルを編集してください。

調整可能なパラメータは2つあります:
cron : 新しいレビューがあるかどうかをチェックする間隔を設定します。デフォルトは 15 */6 * * * で、6時間ごとに15分に実行されます。

参考に crontab.guru を使って、自分のニーズに合わせて設定してください。
ご注意ください:
- Github Action は UTC タイムゾーンを使用しています
- 実行頻度が高いほど、GitHub Actions の実行クレジットを多く消費します。
run : 実行するコマンドを設定します。本文下部の「 実行 」セクションを参照してください。デフォルトは ZReviewTender -r です。
-
デフォルトで Android アプリと Apple(iOS/macOS アプリ)を実行:
ZReviewTender -r -
Android アプリのみ実行:
ZReviewTender -g -
Apple(iOS/macOS アプリ)のみ実行:
ZReviewTender -a
編集が完了したら、右上の「Start commit」をクリックし、「Commit changes」を選択して設定を保存します。
ZReviewTender の手動実行トリガー
前文「6. ZReviewTender の初期化(手動で一度実行)」を参照してください。
Gem を使ったインストール
Gems に慣れている場合は、以下のコマンドで ZReviewTender を直接インストールできます。
gem install ZReviewTender
Gem を使ったインストール(Ruby/Gems に不慣れな方)
Ruby や Gems に不慣れな場合は、以下の手順に従って ZReviewTender をステップバイステップでインストールしてください。
-
macOS は Ruby を標準搭載していますが、新しい Ruby のインストールやバージョン管理には rbenv または rvm の使用を推奨します(私は
2.6.5を使用しています)。 -
rbenv または rvm を使って Ruby 2.6.5 をインストールし、rbenv/rvm の Ruby に切り替えます。
-
which rubyを使って現在使用している Ruby が /usr/bin/ruby でないことを確認します。 -
Ruby 環境が整ったら、以下のコマンドで
ZReviewTenderをインストールします。
gem install ZReviewTender
デプロイ — 機能を自分で拡張したい場合
手動
-
git clone ZReviewTender ソースコード
-
確認と Ruby 環境のセットアップ
-
ディレクトリに移動し、
bundle installを実行して ZReviewTender の依存関係をインストールします。
Processor の作成方法については、後述の記事内容を参照してください。
設定
ZReviewTender — yaml ファイルで設定する Apple/Google レビュー監視ロボット。
[おすすめ] 記事下部の実行コマンド — 「設定ファイルを生成する」を直接ご利用ください:
ZReviewTender -i
直接空の apple.yml と android.yml 設定ファイルを生成します。
Apple (iOS/macOS アプリ)
apple.example.yml ファイルを参照:
⚠️ ダウンロードした
apple.example.ymlは必ずファイル名をapple.ymlに変更してください。
apple.yml:
platform: 'apple'
appStoreConnectP8PrivateKeyFilePath: '' # APPLE STORE CONNECT API のプライベート .p8 キーファイルのパス
appStoreConnectP8PrivateKeyID: '' # APPLE STORE CONNECT API のプライベートキーID
appStoreConnectIssueID: '' # APPLE STORE CONNECT のイシューID
appID: '' # アプリID
...
appStoreConnectIssueID:

-
App Store Connect -> Keys -> App Store Connect API
-
発行者ID:
appStoreConnectIssueID
appStoreConnectP8PrivateKeyID & appStoreConnectP8PrivateKeyFilePath:

-
名前:
ZReviewTender -
アクセス権限:
App Manager

-
appStoreConnectP8PrivateKeyID:
キーID -
appStoreConnectP8PrivateKeyFilePath:
/AuthKey_XXXXXXXXXX.p8、APIキーをダウンロードし、ファイルを config yml と同じディレクトリに配置してください。
appID:

appID: App Store Connect -> App Store -> 一般 -> アプリ情報 -> Apple ID
GCP サービスアカウント
ZReviewTender が使用する Google API サービス(レビュー取得、Google 翻訳、Google Sheet)はすべて Service Account 認証方式を採用しています。
まずは公式手順で GCP とサービスアカウントを作成し、GCP サービスアカウントの認証キー(*.json)をダウンロードして保存してください。
-
自動翻訳機能を使用する場合は、GCPで
Cloud Translation APIが有効になっており、使用するサービスアカウントにも権限が付与されていることを確認してください。 -
Google Sheet に記録する機能を使用する場合は、GCPで
Google Sheets APIとGoogle Drive APIが有効になっていること、および使用するサービスアカウントが追加されていることを確認してください。

Google Play Console (Android アプリ)
参考 android.example.yml ファイル:
⚠️ ダウンロードした
android.example.ymlのファイル名をandroid.ymlに変更してください。
android.yml:
platform: 'android'
packageName: '' # Androidアプリのパッケージ名
keyFilePath: '' # Google Android Publisher APIの認証.jsonファイルのパス
playConsoleDeveloperAccountID: '' # GoogleコンソールのデベロッパーアカウントID
playConsoleAppID: '' # GoogleコンソールのアプリID
......
packageName:

packageName: com.XXXXX は Google Play Console -> ダッシュボード -> アプリ から取得できます。
playConsoleDeveloperAccountID & playConsoleAppID:
Google Play Console -> ダッシュボード -> アプリのページURLから取得可能:
評価メッセージリンクを組み合わせて、チームがリンクをクリックしてすぐに管理画面の評価返信ページにアクセスできるようにします。
keyFilePath:
最も重要な情報、GCPサービスアカウントの認証キー(*.json)
公式ドキュメント の手順に従い、Google Cloud プロジェクトとサービスアカウントを作成し、Google Play Console の Setup → API Access で Google Play Android Developer API を有効化し、プロジェクトをリンクします。GCP からサービスアカウントの JSON キーをダウンロードしてください。


JSON キーのサンプル内容は以下の通りです:
gcp_key.json:
{
"type": "service_account",
"project_id": "XXXX",
"private_key_id": "XXXX",
"private_key": "-----BEGIN PRIVATE KEY-----\nXXXX\n-----END PRIVATE KEY-----\n",
"client_email": "[email protected]",
"client_id": "XXXX",
"auth_uri": "https://accounts.google.com/o/oauth2/auth",
"token_uri": "https://oauth2.googleapis.com/token",
"auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs",
"client_x509_cert_url": "https://www.googleapis.com/robot/v1/metadata/x509/XXXX.iam.gserviceaccount.com"
}
- keyFilePath:
/gcp_key.jsonキーファイルのパス。ファイルは config yml と同じディレクトリに置いてください。
プロセッサー
processors:
- FilterProcessor:
class: "FilterProcessor"
enable: true # 有効にする
keywordsInclude: [] # フィルタリングしたいキーワード
ratingsInclude: [] # フィルタリングしたい評価
territoriesInclude: [] # フィルタリングしたい地域
- GoogleTranslateProcessor: # Google翻訳プロセッサー、レビュー本文をあなたの言語に翻訳します。不要な場合はこのブロックを削除してください。
class: "GoogleTranslateProcessor"
enable: false # 有効にする
googleTranslateAPIKeyFilePath: '' # Google翻訳API認証情報の.jsonファイルパス
googleTranslateTargetLang: 'zh-TW' # 翻訳先の言語
googleTranslateTerritoriesExclude: ["TWN","CHN"] # 翻訳したくないレビューの発信地域(言語)
- SlackProcessor: # Slackプロセッサー、AppレビューをSlackに再送信します。
class: "SlackProcessor"
enable: true # 有効にする
slackTimeZoneOffset: "+08:00" # レビュー作成日時のタイムゾーン
slackAttachmentGroupByNumber: "1" # 1〜100、1つのSlackメッセージに含めるレビュー数
slackBotToken: "" # Slack Botトークン、Slack Botを通じてメッセージを送信
slackBotTargetChannel: "" # Slack Botトークン、Slack Botを通じてメッセージを送信します。(推奨、優先度高)
slackInCommingWebHookURL: "" # SlackインカミングWebhook URL、Webhook経由でメッセージ送信(非推奨、廃止予定)
...More Processors...
ZReviewTender は4つの Processor を備えており、処理の順序はデータ処理の流れに影響します。FilterProcessor->GoogleTranslateProcessor->SlackProcessor->GoogleSheetProcessor。
FilterProcessor:
指定された条件でフィルタリングされた評価のみを処理します。
-
class:
FilterProcessorは調整不要で、lib/Processors/FilterProcessor.rb を指します。 -
enable:
true/falseこの Processor を有効にするかどうか -
keywordsInclude: [“
キーワード1”,“キーワード2”…] これらのキーワードを含むレビューをフィルタリングする -
ratingsInclude: [
1,2…] 1〜5の評価スコアのうち、これらのスコアを含むレビューをフィルタリングする -
territoriesInclude: [“
zh-hant”,”TWN”…] これらの地域(Apple)または言語(Android)を含むレビューをフィルタリングする
GoogleTranslateProcessor:
評価を指定した言語に翻訳する。
-
class:
GoogleTranslateProcessorは調整不要で、lib/Processors/GoogleTranslateProcessor.rb を指します。 -
enable:
true/falseこの Processor を有効にするかどうか -
googleTranslateAPIKeyFilePath:
/gcp_key.jsonGCPサービスアカウントの認証キー ファイルパス*.json。ファイルは config yml と同じディレクトリに配置してください。内容の例は上記の Google Play Console JSON キーの例を参照してください。
(該当の JSON キーのサービスアカウントにCloud Translation APIの使用権限があることを確認してください) -
googleTranslateTargetLang:
zh-TW、en…ターゲット翻訳言語 -
googleTranslateTerritoriesExclude: [“
zh-hant”,”TWN”…] 翻訳不要の地域(Apple)または言語(Android)
SlackProcessor:
評価を Slack に転送する。
-
class:
SlackProcessorは調整不要で、lib/Processors/SlackProcessor.rb を指します。 -
enable:
true/falseこの Processor を有効にするかどうか -
slackTimeZoneOffset:
+08:00レビュー時間の表示タイムゾーン -
slackAttachmentGroupByNumber:
1は、いくつのレビューを1つのメッセージにまとめて送信するかを設定します。デフォルトでは、1つのレビューにつき1つのSlackメッセージが送信されます。 -
slackBotToken:
xoxb-xxxx-xxxx-xxxxSlack Bot Token 、Slack はpostMessagesスコープを含む Slack Bot を作成し、それを使って Slack メッセージを送信することを推奨しています。 -
slackBotTargetChannel:
CXXXXXXグループID(グループ名ではありません)、Slack Botがメッセージを送信するチャンネルグループです。必ずSlack Botをそのグループに追加してください。 -
slackInCommingWebHookURL:
https://hooks.slack.com/services/XXXXX古いIncoming WebHook URLを使ってSlackにメッセージを送信します。注意!Slackはこの方法でのメッセージ送信を推奨していません。
ご注意ください、これはレガシーなカスタム統合であり、チームが Slack と連携するための古い方法です。これらの統合は最新の機能がなく、将来的に廃止され、削除される可能性があります。使用は推奨しません。 代わりに、こちらの後継である Slack apps をご確認ください。
- slackBotToken と slackInCommingWebHookURL について、SlackProcessor は slackBotToken を優先的に使用します。


GoogleSheetProcessor
評価を Google Sheet に記録する。
-
class:
GoogleSheetProcessorは調整不要で、lib/Processors/ のSlackProcessor.rb を指します。 -
enable:
true/falseこの Processor を有効にするかどうか -
googleSheetAPIKeyFilePath:
/gcp_key.jsonGCPサービスアカウント認証キーのファイルパス*.jsonです。ファイルは config yml と同じディレクトリに配置してください。内容の例は上記の Google Play Console JSON キーの例を参照してください。
(該当の JSON キーのサービスアカウントにGoogle Sheets APIとGoogle Drive APIの使用権限があることを確認してください) -
googleSheetTimeZoneOffset:
+08:00レビュー時間のタイムゾーン表示 -
googleSheetID:
Google Sheet ID
Google Sheet のURLから取得可能:https://docs.google.com/spreadsheets/d/googleSheetID/ -
googleSheetName: シート名、例:
Sheet1 -
keywordsInclude: [“
キーワード1”,“キーワード2”…] これらのキーワードを含むレビューをフィルタリングする -
ratingsInclude: [
1,2…] 1〜5の評価スコアのうち、これらのスコアを含むレビューをフィルタリングする -
territoriesInclude: [“
zh-hant”,”TWN”…] これらの地域(Apple)または言語(Android)を含むレビューをフィルタリングする -
values: [] 評価情報のフィールド組み合わせ
%TITLE% 評価タイトル
%BODY% 評価内容
%RATING% 評価スコア 1~5
%PLATFORM% 評価元プラットフォーム Apple または Android
%ID% 評価ID
%USERNAME% 評価者名
%URL% 評価リンク
%TERRITORY% 評価地域(Apple)または評価言語(Android)
%APPVERSION% 評価されたアプリのバージョン
%CREATEDDATE% 評価作成日
例えば私の Google Sheet の列は以下の通りです:
評価スコア,評価タイトル,評価内容,評価情報
則 values は以下のように設定できます:
values: ["%TITLE%","%BODY%","%RATING%","%PLATFORM% - %APPVERSION%"]
カスタム Processor を使って自分のワークフローに接続する
カスタム Processor が必要な場合は、手動デプロイを使用してください。gem 上の ZReviewTender はパッケージ化されており、動的な調整はできません。
您は lib/Processors/ProcessorTemplate.rb を参考にして拡張機能を作成できます:
$lib = File.expand_path('../lib', File.dirname(__FILE__))
require "Models/Review"
require "Models/Processor"
require "Helper"
require "ZLogger"
# config.yml に追加してください:
#
# processors:
# - ProcessorTemplate:
# class: "ProcessorTemplate"
# parameter1: "value"
# parameter2: "value"
# parameter3: "value"
# ...
#
class ProcessorTemplate < Processor
def initialize(config, configFilePath, baseExecutePath)
# Processor を初期化
# config からパラメータを取得 例: config["parameter1"]
# configFilePath: 設定ファイルのパス(apple.yml/android.yml)
# baseExecutePath: ユーザーの実行パス
end
def processReviews(reviews, platform)
if reviews.length < 1
return reviews
end
## レビューに対して行いたい処理を実装してください...
## 処理後のレビューを返す
return reviews
end
end
initialize は以下を提供します:
-
config Object: config yml 内の設定値に対応しています
-
configFilePath: 使用する config yml ファイルのパス
-
baseExecutePath: ユーザーが ZReviewTender を実行しているパス
processReviews(reviews, platform):
新しいレビューを取得した後、この関数に入り、Processorが処理する機会を与えます。処理が完了したら、結果のReviewsをreturnしてください。
Review データ構造は lib/Models/ Review.rb に定義されています。
注釈
XXXterritorXXX パラメータ:
-
Apple 使用地域:TWM/JPN…
-
Android 使用言語:zh-hant/en/…
もし特定の Processor が不要な場合:
enable: false を設定するか、該当の Processor の設定ブロックを削除してください。
Processors の実行順序はご要望に応じて自由に調整可能です:
例)まず Filter を実行し、その後に翻訳、Slack、Google Sheet へのログ記録を実行…
実行
⚠️ Gem を使う場合は直接
ZReviewTenderを実行してください。手動でプロジェクトをデプロイする場合はbundle exec ruby bin/ZReviewTenderを使ってください。
設定ファイルの生成:
ZReviewTender -i
apple.example.yml と android.example.yml から、現在の実行ディレクトリの config/ フォルダに apple.yml と android.yml を生成します。
Apple と Android のレビュー取得を実行:
ZReviewTender -r
- デフォルトで
/config/以下のapple.ymlとandroid.yml設定を読み込みます
Apple と Android のレビュー取得および指定設定ファイルディレクトリの実行:
ZReviewTender --run=設定ファイルディレクトリ
- デフォルトで
/config/以下のapple.ymlとandroid.yml設定を読み込みます
Apple のレビュー取得のみ実行:
ZReviewTender -a
- デフォルトで
/config/以下のapple.yml設定を読み込みます
Appleのレビュー取得のみ実行 & 指定設定ファイルの場所:
ZReviewTender --apple=apple.yml設定ファイルの場所
Android のレビュー収集のみ実行:
ZReviewTender -g
- デフォルトで
/config/下のandroid.yml設定を読み込みます
Android の評価取得のみ実行 & 設定ファイルの場所指定:
ZReviewTender --googleAndroid=android.yml設定ファイルの場所
実行記録をクリアして初期設定に戻す
ZReviewTender -d
/latestCheckTimestamp 内の Timestamp 記録ファイルを削除し、初期状態に戻します。再度実行すると、再び init success メッセージを受け取ります:

現在の ZReviewTender バージョン
ZReviewTender -v
現在の ZReviewTender の最新バージョンは RubyGem で確認できます。
ZReviewTender を最新版に更新する (rubygem のみ)
ZReviewTender -n
初回実行

初回実行成功時に指定した Slack チャンネルへ初期化成功メッセージを送信し、実行ディレクトリ内に latestCheckTimestamp/Apple と latestCheckTimestamp/Android ファイルを生成して、最後に取得したレビューのタイムスタンプを記録します。

また、実行エラーを記録する execute.log も生成されます。

スケジュールの継続実行設定
スケジュールを設定して定期的に(crontab)新しいレビューの取得を継続的に実行します。ZReviewTender は latestCheckTimestamp で前回取得したレビューのタイムスタンプから今回の取得時間までの新しいレビューを取得し、タイムスタンプの記録ファイルを更新します。
例:crontab: 15 */6 * * * ZReviewTender -r
また、Android API は過去7日間に追加または編集されたレビューのみを取得できるため、スケジュールの周期は7日を超えないように注意してください。レビューの取りこぼしを防ぐためです。

https://developers.google.com/android-publisher/reply-to-reviews#retrieving_a_set_of_reviews
Github Action デプロイ

name: ZReviewTender
on:
workflow_dispatch:
schedule:
- cron: "15 */6 * * *" #6時間ごとに実行、上記のcrontabを参考に設定を変更可能
jobs:
ZReviewTender:
runs-on: ubuntu-latest
steps:
- name: ZReviewTender Automatic Bot
uses: ZhgChgLi/ZReviewTender@main
with:
command: '-r' #Apple & iOSアプリのレビューをチェック、上記を参考に他のコマンドに変更可能
⚠️️️️️ 再度警告!
設定ファイルやキーが公開されないように必ず注意してください。これらの機密情報が漏洩すると、AppやSlackの権限が悪用される可能性があります。作者は不正使用に関して一切の責任を負いません。
もし予期せぬエラーが発生した場合は、Issueを作成してください ログ情報を添えていただければ、できるだけ早く修正いたします!
完了
使用方法の説明は以上です。次は開発の裏話を共有します。
=========================
Appレビューとの戦い
去年まとめた AppStore APP’s Reviews Slack Bot に関する話 と関連技術を使って実現した ZReviewsBot — Slack App Review 通知ボット で、アプリの最新レビューを社内ワークフローに統合する件は一段落したと思っていましたが、今年 Apple が App Store Connect API を更新 し、この取り組みがさらに進化できるようになりました。
昨年まとめた Apple iOS/macOS アプリのレビュー取得ソリューション:
-
Public URL API (RSS) ⚠️: 柔軟なフィルタリングができず、提供される情報も少なく、件数制限があり、時々データの乱れが発生して非常に不安定です;公式は将来的に廃止する可能性があります
-
Fastlane — SpaceShip を使って複雑なウェブ操作やセッション管理をラップし、App Store Connect の管理画面から評価データを取得します(ウェブブラウザのエミュレーターでスクレイピングしてデータを取得するイメージです)。
昨年の方法に従うと、方法二しか使えませんでしたが、効果はあまり良くありませんでした。Session は期限切れになり、手動で定期的に更新する必要があり、IP が変わるとすぐに Session が無効になるため、CI/CD サーバー上での運用はできません。
![]()
important-note-about-session-duration Fastlaneによる
今年、Apple が App Store Connect API を更新したという知らせを受けてすぐに、新しいレビュー監視ロボットの再設計に取り掛かりました。公式 API の採用に加え、以前の構造設計の最適化と Ruby の使い方にもさらに習熟しました。
App Store Connect API 開発で直面した問題
- List All Customer Reviews for an App このエンドポイントはアプリのバージョン情報を返しません。
とても奇妙ですが、まずこのエンドポイントを使って最新のレビューを絞り込み、次に List All App Store Versions for an App と List All Customer Reviews for an App Store Version を組み合わせて App のバージョン情報を取得しています。
AndroidpublisherV3 開発で直面した問題
-
API はすべてのレビュー一覧を取得する方法を提供しておらず、直近7日間に追加または編集されたレビューのみ取得可能です。
-
同様に JWT を使って Google API に接続する(関連ライブラリに依存しない例:google-apis-androidpublisher_v3 など)
-
Google API の JWT 生成&使用例を添付します:
require "jwt"
require "time"
payload = {
iss: "GCP API 認証キー (*.json) ファイルの client_email フィールド",
sub: "GCP API 認証キー (*.json) ファイルの client_email フィールド",
scope: ["https://www.googleapis.com/auth/androidpublisher"].join(' '),
aud: "GCP API 認証キー (*.json) ファイルの token_uri フィールド",
iat: Time.now.to_i,
exp: Time.now.to_i + 60*20
}
rsa_private = OpenSSL::PKey::RSA.new("GCP API 認証キー (*.json) ファイルの private_key フィールド")
token = JWT.encode payload, rsa_private, 'RS256', header_fields = {kid:"GCP API 認証キー (*.json) ファイルの private_key_id フィールド", typ:"JWT"}
uri = URI("API 認証キー (*.json) ファイルの token_uri フィールド")
https = Net::HTTP.new(uri.host, uri.port)
https.use_ssl = true
request = Net::HTTP::Post.new(uri)
request.body = "grant_type=urn%3Aietf%3Aparams%3Aoauth%3Agrant-type%3Ajwt-bearer&assertion=#{token}"
response = https.request(request).read_body
bearer = result["access_token"]
### ベアラートークンを使用
uri = URI("https://androidpublisher.googleapis.com/androidpublisher/v3/applications/APP_PACKAGE_NAME/reviews")
https = Net::HTTP.new(uri.host, uri.port)
https.use_ssl = true
request = Net::HTTP::Get.new(uri)
request['Authorization'] = "Bearer #{bearer}";
response = https.request(request).read_body
result = JSON.parse(response)
# 成功!
Post MediumからZMediumToMarkdownによって変換されました。



コメント