Home ZReviewTender — Free Open Source App Reviews Monitoring Bot
Post
Cancel

ZReviewTender — Free Open Source App Reviews Monitoring Bot

ZReviewTender — Free Open Source App Reviews Monitoring Bot

Real-time monitoring of the latest app reviews and providing instant feedback to improve collaboration efficiency and consumer satisfaction

[ZhgChgLi](https://github.com/ZhgChgLi){:target="_blank"} [ZReviewTender](https://github.com/ZhgChgLi/ZReviewTender){:target="_blank"}

ZhgChgLi / ZReviewTender

ZhgChgLi / ZReviewTender

App Reviews to Slack Channel

App Reviews to Slack Channel

ZReviewTender Automatically monitors the latest user reviews of App Store iOS/macOS apps and Google Play Android apps, and provides continuous integration tools to integrate into team workflows, improving collaboration efficiency and consumer satisfaction.

Key Features

  • Retrieve review lists from App Store iOS/macOS apps and Google Play Android apps and filter out the latest reviews that have not been crawled yet
  • [Default Feature] Forward the latest crawled reviews to Slack, and click the message timestamp link to quickly enter the backend to reply to reviews
  • [Default Feature] Support using Google Translate API to automatically translate reviews from non-specified languages/regions into your language
  • [Default Feature] Support automatic recording of reviews to Google Sheets
  • Support flexible expansion, in addition to the included default features, you can still develop the required features according to the team workflow and integrate them into the tool e.g. Forward reviews to Discord, Line, Telegram…
  • Use timestamps to record crawl positions to prevent duplicate crawling of reviews
  • Support filtering features, you can specify to crawl only reviews with certain ratings, containing certain keywords, or from certain regions/languages
  • Apple provides a stable and reliable source of App Store app review data based on the new App Store Connect API, no longer relying on unreliable XML data or Fastlane Spaceship sessions that expire and require regular manual maintenance
  • Android also uses the official AndroidpublisherV3 API to fetch review data
  • Support deployment using Github Repo w/ Github Action, allowing you to quickly and freely set up the ZReviewTender App Reviews bot
  • 100% Ruby @ RubyGem

Comparison with Similar Services

App Reviews Workflow Integration Example (in Pinkoi)

Problem:

Reviews in the marketplace are very important for products, but it is a very manual and repetitive task to communicate and refer.

Because you have to manually check for new reviews from time to time, and if there are customer service issues, forward them to customer service for assistance. It’s repetitive and manual.

Through the ZReviewTender review bot, reviews are automatically forwarded to the Slack Channel, allowing everyone to quickly receive the latest review information, and track and discuss in real-time. It also allows the entire team to understand the current user reviews and suggestions for the product.

For more information, refer to: 2021 Pinkoi Tech Career Talk — High-Efficiency Engineering Team Demystified.

Deployment — Using Default Features Only

If you only need the default features of ZReviewTender (to Slack/Google Translate/Filter), you can use the following quick deployment method.

ZReviewTender has been packaged and released on RubyGems, and you can quickly and easily install and use ZReviewTender with RubyGems.

  • No hosting space required ✅
  • No environment requirements ✅
  • No need to understand engineering principles ✅
  • Complete the Config file configuration to complete the deployment ✅
  • Deployment can be completed in 8 steps ✅
  • Completely free ✅ Github Action provides each account with 2,000+ minutes/month of execution time. Running ZReviewTender review fetching once only takes about 15-30 seconds. By default, it runs every 6 hours, 4 times a day, consuming only about 60 minutes per month. Github Private Repo can be created without any limit for free.
  1. Go to the ZReviewTender Template Repo: ZReviewTender-deploy-with-github-action

Click the “Use this template” button at the top right.

  1. Create Repo

  • Repository name: Enter the name of the Repo project you want
  • Access: Private

⚠️⚠️ Be sure to create a Private Repo ⚠️⚠️

Because you will upload settings and private keys to the project

Finally, click the “Create repository from template” button at the bottom.

  1. Confirm that your created Repo is a Private Repo

Confirm that the Repo name at the top right shows “🔒” and the Private label.

If not, it means you created a Public Repo which is very dangerous, please go to the top Tab “Settings” -> “General” -> Bottom “Danger Zone” -> “Change repository visibility” -> “Make private” to change it back to Private Repo.

  1. Wait for Project init to succeed

You can check the Badge in the Readme on the Repo homepage

If it shows passing, it means init was successful.

Or click the top Tab “Actions” -> wait for the “Init ZReviewTender” Workflow to complete:

Execution status will change to 3 “✅ Init ZReviewTender” -> Project init successful.

  1. Confirm if the init files and directories are correctly created

Click the “Code” tab above to return to the project directory. If the project init is successful, you will see:

  • Directory: config/
  • File: config/android.yml
  • File: config/apple.yml
  • Directory: latestCheckTimestamp/
  • File: latestCheckTimestamp/.keep
  1. Complete Configuration for android.yml & apple.yml

Enter the config/ directory to complete the configuration of android.yml & apple.yml files.

Click to enter the config YML file you want to edit and click the “✏️” in the upper right corner to edit the file.

Refer to the “ Settings “ section below to complete the configuration of android.yml & apple.yml.

After editing, you can directly save the settings by clicking “Commit changes” below.

Upload the corresponding Key files to the config/ directory:

In the config/ directory, select “Add file” -> “Upload files” in the upper right corner.

Upload the corresponding Key and external file paths configured in the config yml to the config/ directory, drag the files to the “upper block” -> wait for the files to upload -> directly “Commit changes” below to save.

After uploading, go back to the /config directory to check if the files are correctly saved & uploaded.

  1. Initialize ZReviewTender (manually trigger execution once)

Click the “Actions” tab above -> select “ZReviewTender” on the left -> select “Run workflow” on the right -> click the “Run workflow” button to execute ZReviewTender once.

After clicking, refresh the webpage and you will see:

Click “ZReviewTender” to view the execution status.

Expand the “ Run ZreviewTender -r “ block to view the execution log.

Here you can see an error because I haven’t configured my config yml file properly.

Go back and adjust the android/apple config yml, then return to step 6 and trigger the execution again.

Check the log of the “ ZReviewTender -r “ block to confirm successful execution!

The Slack channel designated to receive the latest review messages will also show an init success message 🎉

  1. Done! 🎉 🎉 🎉

Configuration complete! From now on, the latest reviews within the period will be automatically fetched and forwarded to your Slack channel every 6 hours!

You can check the latest execution status at the top of the Readme on the Repo homepage:

If an error occurs, it means there was an execution error. Please go to Actions -> ZReviewTender to view the records; if there is an unexpected error, please create an Issue with the record information, and it will be fixed as soon as possible!

❌❌❌ When an error occurs, Github will also send an email notification, so you don’t have to worry about the bot crashing without anyone noticing!

Github Action Adjustment

You can configure the Github Action execution rules according to your needs.

Click on the “Actions” tab above -> “ZReviewTender” on the left -> “ ZReviewTender.yml “ on the top right

Click the “✏️” on the top right to edit the file.

There are two parameters that can be adjusted:

cron: Set how often to check for new reviews. The default is 15 */6 * * *, which means it will run every 6 hours and 15 minutes.

You can refer to crontab.guru to configure it according to your needs.

Please note:

  1. Github Action uses the UTC time zone
  1. The higher the execution frequency, the more Github Action execution quota will be consumed

run: Set the command to be executed. You can refer to the “ Execution “ section below. The default is ZReviewTender -r

  • Default execution for Android App & Apple (iOS/macOS App): ZReviewTender -r
  • Execute only for Android App: ZReviewTender -g
  • Execute only for Apple (iOS/macOS App) App: ZReviewTender -a

After editing, click “Start commit” on the top right and select “Commit changes” to save the settings.

Manually Trigger ZReviewTender

Refer to the previous section “6. Initialize ZReviewTender (Manually trigger execution once)”

Install Using Gem

If you are familiar with Gems, you can directly use the following command to install ZReviewTender

1
gem install ZReviewTender

Install Using Gem (Not familiar with Ruby/Gems)

If you are not familiar with Ruby or Gems, you can follow the steps below to install ZReviewTender step by step

  1. Although macOS comes with Ruby, it is recommended to use rbenv or rvm to install a new Ruby and manage Ruby versions (I use 2.6.5)
  2. Use rbenv or rvm to install Ruby 2.6.5, and switch to rbenv/rvm’s Ruby
  3. Use which ruby to confirm that the current Ruby in use is not the system Ruby /usr/bin/ruby
  4. Once the Ruby environment is OK, use the following command to install ZReviewTender
1
gem install ZReviewTender

Deployment — Want to Extend Functionality Yourself

Manual

  1. git clone ZReviewTender Source Code
  2. Confirm & improve the Ruby environment
  3. Enter the directory and run bundle install to install related dependencies for ZReviewTender

The method for creating a Processor can be referred to in the later content of the article.

Configuration

ZReviewTender — Use a yaml file to configure the Apple/Google review bot.

[Recommendation] Directly use the command at the bottom of the article — “Generate Configuration File”:

1
ZReviewTender -i

Directly generate blank apple.yml & android.yml configuration files.

Apple (iOS/macOS App)

Refer to the apple.example.yml file:

⚠️ After downloading apple.example.yml, remember to rename the file to apple.yml

apple.yml:

1
2
3
4
5
6
platform: 'apple'
appStoreConnectP8PrivateKeyFilePath: '' # APPLE STORE CONNECT API PRIVATE .p8 KEY File Path
appStoreConnectP8PrivateKeyID: '' # APPLE STORE CONNECT API PRIVATE KEY ID
appStoreConnectIssueID: '' # APPLE STORE CONNECT ISSUE ID
appID: '' # APP ID
...

appStoreConnectIssueID:

appStoreConnectP8PrivateKeyID & appStoreConnectP8PrivateKeyFilePath:

  • Name: ZReviewTender
  • Access: App Manager

  • appStoreConnectP8PrivateKeyID: Key ID
  • appStoreConnectP8PrivateKeyFilePath: /AuthKey_XXXXXXXXXX.p8, Download API Key, and place the file in the same directory as the config yml.

appID:

appID: App Store Connect -> App Store -> General -> App Information -> Apple ID

GCP Service Account

The Google API services used by ZReviewTender (fetching store reviews, Google Translate, Google Sheet) all use Service Account authentication.

You can follow the official steps to create GCP & Service Account to download and save the GCP Service Account credentials (*.json).

  • To use the auto-translate feature, make sure GCP has enabled Cloud Translation API and the Service Account is added.
  • To use the record to Google Sheet feature, make sure GCP has enabled Google Sheets API, Google Drive API, and the Service Account is added.

Google Play Console (Android App)

Refer to the android.example.yml file:

⚠️ After downloading android.example.yml, remember to rename the file to android.yml

android.yml:

1
2
3
4
5
6
platform: 'android'
packageName: '' # Android App Package Name
keyFilePath: '' # Google Android Publisher API Credential .json File Path
playConsoleDeveloperAccountID: '' # Google Console Developer Account ID
playConsoleAppID: '' # Google Console App ID
......

packageName:

packageName: com.XXXXX can be obtained from Google Play Console -> Dashboard -> App

playConsoleDeveloperAccountID & playConsoleAppID:

Can be obtained from the URL on the Google Play Console -> Dashboard -> App page:

https://play.google.com/console/developers/ playConsoleDeveloperAccountID /app/ playConsoleAppID /app-dashboard

This will be used to generate a review message link, allowing the team to quickly access the backend review reply page by clicking the link.

keyFilePath:

The most important information, GCP Service Account credential key (*.json)

Follow the steps in the official documentation to create a Google Cloud Project & Service Account, then go to Google Play Console -> Setup -> API Access to enable the Google Play Android Developer API and link the project. Download the JSON key from GCP.

Example content of the JSON key:

gcp_key.json:

1
2
3
4
5
6
7
8
9
10
11
12
{
    "type": "service_account",
    "project_id": "XXXX",
    "private_key_id": "XXXX",
    "private_key": "-----BEGIN PRIVATE KEY-----\nXXXX\n-----END PRIVATE KEY-----\n",
    "client_email": "XXXX@XXXX.iam.gserviceaccount.com",
    "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 Key file path, place the file in the same directory as the config yml.

Processors

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
processors:
    - FilterProcessor:
        class: "FilterProcessor"
        enable: true # enable
        keywordsInclude: [] # keywords you want to filter out
        ratingsInclude: [] # ratings you want to filter out
        territoriesInclude: [] # territories you want to filter out
    - GoogleTranslateProcessor: # Google Translate Processor, will translate review text to your language, you can remove whole block if you don't needed it.
        class: "GoogleTranslateProcessor"
        enable: false # enable
        googleTranslateAPIKeyFilePath: '' # Google Translate API Credential .json File Path
        googleTranslateTargetLang: 'zh-TW' # Translate to what Language
        googleTranslateTerritoriesExclude: ["TWN","CHN"] # Review origin Territory (language) that you don't want to translate.
    - SlackProcessor: # Slack Processor, resend App Review to Slack.
        class: "SlackProcessor"
        enable: true # enable
        slackTimeZoneOffset: "+08:00" # Review Created Date TimeZone
        slackAttachmentGroupByNumber: "1" # 1~100, how many review message in 1 slack message.
        slackBotToken: "" # Slack Bot Token, send slack message throught Slack Bot.
        slackBotTargetChannel: "" # Slack Bot Token, send slack message throught Slack Bot. (recommended, first priority)
        slackInCommingWebHookURL: "" # Slack In-Comming WebHook URL, Send slack message throught In-Comming WebHook, not recommended, deprecated.
    ...More Processors...

ZReviewTender comes with four processors, and the order affects the data processing flow: FilterProcessor -> GoogleTranslateProcessor -> SlackProcessor -> GoogleSheetProcessor.

FilterProcessor:

Filters the fetched reviews based on specified conditions, only processing reviews that meet the criteria.

  • class: FilterProcessor No need to adjust, points to lib/Processors/ FilterProcessor .rb
  • enable: true / false Enable this processor or not
  • keywordsInclude: [“ keyword1 ”,“ keyword2 ”…] Filters reviews that contain these keywords
  • ratingsInclude: [ 1 , 2 …] 1~5 Filters reviews that include these ratings
  • territoriesInclude: [“ zh-hant ”,” TWN ”…] Filters reviews that include these regions (Apple) or languages (Android)

GoogleTranslateProcessor:

Translate the reviews into the specified language.

  • class: GoogleTranslateProcessor No adjustment needed, points to lib/Processors/ GoogleTranslateProcessor .rb
  • enable: true / false Enable this Processor or Not
  • googleTranslateAPIKeyFilePath: /gcp_key.json GCP Service Account credential key File Path *.json, place the file in the same directory as the config yml, refer to the Google Play Console JSON key example above. (Please ensure that the service account of the JSON key has Cloud Translation API permissions)
  • googleTranslateTargetLang: zh-TW, en …target translation language
  • googleTranslateTerritoriesExclude: [“ zh-hant ”,” TWN ”…] Territories (Apple) or languages (Android) that do not need translation

SlackProcessor:

Forward reviews to Slack.

  • class: SlackProcessor No adjustment needed, points to lib/Processors/ SlackProcessor .rb
  • enable: true / false Enable this Processor or Not
  • slackTimeZoneOffset: +08:00 Review time display time zone
  • slackAttachmentGroupByNumber: 1 Set how many Reviews to combine into one message to speed up sending; default is 1 Review per 1 Slack message.
  • slackBotToken: xoxb-xxxx-xxxx-xxxx Slack Bot Token, Slack recommends creating a Slack Bot with postMessages Scope and using it to send Slack messages
  • slackBotTargetChannel: CXXXXXX Group ID ( not the group name ), the Slack Bot will send to which Channel group; and you need to add your Slack Bot to that group
  • slackInCommingWebHookURL: https://hooks.slack.com/services/XXXXX Use the old InComming WebHookURL to send messages to Slack, note! Slack does not recommend continuing to use this method to send messages.

Please note, this is a legacy custom integration — an outdated way for teams to integrate with Slack. These integrations lack newer features and they will be deprecated and possibly removed in the future. We do not recommend their use. Instead, we suggest that you check out their replacement: Slack apps.

  • slackBotToken and slackInCommingWebHookURL, SlackProcessor will preferentially choose to use slackBotToken

GoogleSheetProcessor

Record reviews to Google Sheet.

  • class: GoogleSheetProcessor No adjustment needed, points to lib/Processors/ SlackProcessor .rb
  • enable: true / false Enable this Processor or Not
  • googleSheetAPIKeyFilePath: /gcp_key.json GCP Service Account credential key File Path *.json, place the file in the same directory as the config yml, refer to the Google Play Console JSON key example above. (Please ensure that the service account of the JSON key has Google Sheets API, Google Drive API permissions)
  • googleSheetTimeZoneOffset: +08:00 Review time display time zone
  • googleSheetID: Google Sheet ID Can be obtained from the Google Sheet URL: https://docs.google.com/spreadsheets/d/ googleSheetID /
  • googleSheetName: Sheet name, e.g. Sheet1
  • keywordsInclude: [“ keyword1 ”,“ keyword2 ”…] Filter reviews that contain these keywords
  • ratingsInclude: [ 1, 2 …] 1~5 Filter reviews that contain these rating scores
  • territoriesInclude: [“ zh-hant ”,” TWN ”…] Filter reviews that contain these territories (Apple) or languages (Android)
  • values: [ ] Combination of review information fields
1
2
3
4
5
6
7
8
9
10
%TITLE% Review Title
%BODY% Review Content
%RATING% Review Rating 1~5
%PLATFORM% Review Source Platform Apple or Android
%ID% Review ID
%USERNAME% Review Username
%URL% Review URL
%TERRITORY% Review Territory (Apple) or Review Language (Android)
%APPVERSION% Reviewed App Version
%CREATEDDATE% Review Creation Date

For example, my Google Sheet columns are as follows:

1
Review Rating,Review Title,Review Content,Review Information

Then values can be set as:

1
values: ["%TITLE%","%BODY%","%RATING%","%PLATFORM% - %APPVERSION%"]

Custom Processor to Integrate Your Workflow

If you need a custom Processor, please use manual deployment, as the gem version of ZReviewTender is packaged and cannot be dynamically adjusted.

You can refer to lib/Processors/ProcessorTemplate.rb to create your extension:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
$lib = File.expand_path('../lib', File.dirname(__FILE__))

require "Models/Review"
require "Models/Processor"
require "Helper"
require "ZLogger"

# Add to config.yml:
#
# processors:
#   - ProcessorTemplate:
#       class: "ProcessorTemplate"
#       parameter1: "value"
#       parameter2: "value"
#       parameter3: "value"
#       ...
#

class ProcessorTemplate < Processor

    def initialize(config, configFilePath, baseExecutePath)
        # init Processor
        # get parameter from config e.g. config["parameter1"]
        # configFilePath: file path of config file (apple.yml/android.yml)
        # baseExecutePath: user execute path
    end

    def processReviews(reviews, platform)
        if reviews.length < 1
            return reviews
        end

        ## do what you want to do with reviews...
        
        ## return result reviews
        return reviews
    end
end

initialize will provide:

  • config Object: Corresponding settings in the config yml
  • configFilePath: Path of the used config yml file
  • baseExecutePath: Path where the user executes ZReviewTender

processReviews(reviews, platform):

After fetching new reviews, this function will be called to allow the Processor to handle them. Please return the resulting Reviews after processing.

Review data structure is defined in lib/Models/ Review.rb

Notes

XXXterritorXXX parameter:

  • Apple Region: TWM/JPN…
  • Android Language: zh-hant/en/…

If a Processor is not needed: You can set enable: false or directly remove the Processor Config Block.

1
2
3
4
5
6
7
8
9
10
**Processors execution order can be adjusted according to your needs:**
e.g. Execute Filter first, then Translation, then Slack, then Log to Google Sheet...
### Execution

> ⚠️ Use Gem to directly run `ZReviewTender`, if it's a manual deployment project, please use `bundle exec ruby bin/ZReviewTender` to execute.

#### Generate configuration files:
```css
ZReviewTender -i

Generate apple.yml & android.yml from apple.example.yml & android.example.yml to the config/ directory in the current execution directory.

Execute Apple & Android review scraping:

1
ZReviewTender -r
  • By default, read the apple.yml & android.yml settings under /config/

Execute Apple & Android review scraping & specify configuration file directory:

1
ZReviewTender --run=configuration file directory
  • By default, read the apple.yml & android.yml settings under /config/

Execute only Apple review scraping:

1
ZReviewTender -a
  • By default, read the apple.yml settings under /config/

Execute only Apple review scraping & specify configuration file location:

1
ZReviewTender --apple=apple.yml configuration file location

Execute only Android review scraping:

1
ZReviewTender -g
  • By default, read the android.yml settings under /config/

Execute only Android review scraping & specify configuration file location:

1
ZReviewTender --googleAndroid=android.yml configuration file location

Clear execution records and return to initial settings

1
ZReviewTender -d

This will delete the Timestamp record file in /latestCheckTimestamp, returning to the initial state. Re-executing the scraping will receive the init success message again:

Current ZReviewTender version

1
ZReviewTender -v

Displays the latest version number of ZReviewTender on RubyGem.

Update ZReviewTender to the latest version (rubygem only)

1
ZReviewTender -n

First execution

The first successful execution will send an initialization success message to the specified Slack Channel and generate latestCheckTimestamp/Apple and latestCheckTimestamp/Android files in the corresponding execution directory to record the last scraped review Timestamp.

Additionally, an execute.log will be generated to record execution errors.

Set up a schedule for continuous execution

Set up a schedule (using crontab) to continuously scrape new reviews. ZReviewTender will scrape new reviews from the last scraped review Timestamp recorded in latestCheckTimestamp to the current scraping time and update the Timestamp record file.

e.g. crontab: 15 */6 * * * ZReviewTender -r

Additionally, note that since the Android API only provides reviews added or edited in the last 7 days, the schedule cycle should not exceed 7 days to avoid missing reviews.

[https://developers.google.com/android-publisher/reply-to-reviews#retrieving_a_set_of_reviews](https://developers.google.com/android-publisher/reply-to-reviews#retrieving_a_set_of_reviews){:target="_blank"}

https://developers.google.com/android-publisher/reply-to-reviews#retrieving_a_set_of_reviews

Github Action Deployment

[ZReviewTender App Reviews Automatic Bot](https://github.com/marketplace/actions/zreviewtender-app-reviews-automatic-bot){:target="_blank"}

ZReviewTender App Reviews Automatic Bot

1
2
3
4
5
6
7
8
9
10
11
12
13
14
name: ZReviewTender
on:
  workflow_dispatch:
  schedule:
    - cron: "15 */6 * * *" # Runs every six hours, you can refer to the above crontab to change the settings

jobs:
  ZReviewTender:
    runs-on: ubuntu-latest
    steps:
    - name: ZReviewTender Automatic Bot
      uses: ZhgChgLi/ZReviewTender@main
      with:
        command: '-r' # Executes Apple & iOS App review check, you can refer to the above to change to other execution commands

⚠️️️️️ Warning Again!

Be sure to ensure that your configuration files and keys cannot be publicly accessed, as the sensitive information within them could lead to App/Slack permissions being stolen; the author is not responsible for any misuse.

If any unexpected errors occur, please create an Issue with the log information, and it will be fixed as soon as possible!

Done

The tutorial ends here, next is the behind-the-scenes development story.

=========================

The War with App Reviews

I thought last year’s summary of AppStore APP’s Reviews Slack Bot and the related technology implementation of ZReviewsBot — Slack App Review Notification Bot would conclude the integration of the latest App reviews into the company’s workflow; unexpectedly, Apple updated the App Store Connect API this year, allowing this matter to continue evolving.

Last year’s solution for fetching Apple iOS/macOS App reviews:

  • Public URL API (RSS) ⚠️: Cannot flexibly filter, provides limited information, has a quantity limit, and we occasionally encounter data disorder issues, very unstable; might be deprecated by the official in the future
  • Using Fastlane SpaceShip to encapsulate complex web operations and session management, fetching review data from the App Store Connection backend (equivalent to running a web simulator crawler to fetch data from the backend).

Following last year’s method, only the second method can be used, but the effect is not perfect; the session will expire, requiring manual periodic updates, and cannot be placed on the CI/CD server because the session will expire immediately if the IP changes.

[important-note-about-session-duration](https://docs.fastlane.tools/best-practices/continuous-integration/#important-note-about-session-duration){:target="_blank"} by Fastlane

important-note-about-session-duration by Fastlane

After receiving the news that Apple updated the App Store Connect API this year, I immediately started redesigning the new review bot. In addition to using the official API, I also optimized the previous architecture design and became more familiar with Ruby usage.

Issues encountered during the development of App Store Connect API

It’s very strange, so I had to workaround by first hitting this endpoint to filter out the latest reviews, then hitting List All App Store Versions for an App & List All Customer Reviews for an App Store Version to combine the App version information.

Issues encountered during the development of AndroidpublisherV3

  • The API does not provide a method to get all reviews, only reviews added/edited in the last 7 days.
  • Also uses JWT to connect to Google API (without relying on related libraries e.g. google-apis-androidpublisher_v3)
  • Here is an example of generating & using Google API JWT:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
require "jwt"
require "time"

payload = {
  iss: "client_email field in the GCP API service account key (*.json) file",
  sub: "client_email field in the GCP API service account key (*.json) file",
  scope: ["https://www.googleapis.com/auth/androidpublisher"].join(' '),
  aud: "token_uri field in the GCP API service account key (*.json) file",
  iat: Time.now.to_i,
  exp: Time.now.to_i + 60*20
}

rsa_private = OpenSSL::PKey::RSA.new("private_key field in the GCP API service account key (*.json) file")
token = JWT.encode payload, rsa_private, 'RS256', header_fields = {kid:"private_key_id field in the GCP API service account key (*.json) file", typ:"JWT"}

uri = URI("token_uri field in the GCP API service account key (*.json) file")
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"]

### use bearer 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)

# success!

If you have any questions or suggestions, feel free to contact me.

===

本文中文版本

===

This article was first published in Traditional Chinese on Medium ➡️ View Here


This post is licensed under CC BY 4.0 by the author.

App Store Connect API Now Supports Reading and Managing Customer Reviews

Pinkoi 2022 Open House for GenZ — 15 Mins Career Talk