2014/07/20

Android:AppEngineBackend with GCMメモ

Google Cloud Messaging for Android(GCM)を利用するためのメモ。

メモ:

  • 最大4kbのペイロード・データのメッセージを送出可能
  • Android2.2以上かつGooglePlayStoreがインストールされた端末が必要
  • Android3.0以前の端末ではGoogleアカウントがセットアップされている必要がある
  • GCMはGoogle Play serviceに組み込まれた(com.google.android.gms.gcm)
  • 従来のAPI群は非推奨に(com.google.android.gcm)
  • GoogleCloudMessaging(API)の利用にはGoogle Play services version 3.1以上が必要
  • メッセージ送信時に対象デバイスがオフラインであってもGCMはこれをキューイング/ストア>再送する機能を持つ
  • 3rdPartyサーバはexponential backoffの方式を組み込み、GCMサーバと通信すること
  • GCMメッセージはアプリ固有のPermission付きBroadcastIntent経由で通知される
  • GCMメッセージを受信すると対象アプリが起動されるため、メッセージ監視のためにアプリ起動し続ける必要はない
  • メッセージ処理はWakeLockを取得してService上で実行するが吉
  • GCMメッセージを受信したくない場合はunregisterも可能
  • Genymotionを使用する場合のBackendサーバアドレスは10.0.3.2

GCM基本フロー

  1. アプリケーションはGCMを有効化するための登録を行う
  2. 3rdPartyサーバはデバイス向けメッセージをGCMに送信
  3. アプリケーションはGCMからメッセージを受信する

準備するもの

  1. Google API Projectの作成Google Developers Console
  2. Project Numberを控える(GCM sender IDとして使用.)
  3. API \& auth.からGoogle Cloud Messaging for Androidを有効化.
  4. GCMのServer Keyを作成しAPI Key取得(3rdPartyサーバとGCMサーバ間認証で使用)参考:Obtaining an API Key

3rdPartyサーバの作成

GCMサーバ(GCM connection server)とやりとりするサーバを作成する必要があります。
Implementing GCM Server

App Engine Backend with GCM

試験用途であればApp Engine Backend with Google Cloud Messagingで手軽にGCMバックエンドを作成できます。
利用するには新規ModuleとしてBackendモジュールを作成します(AndroidStudio0.8.2以降)。

Backendモジュールの作成から実行までの詳細手順は下記を参考。
“App Engine Backend with Google Cloud Messaging” Template

Backendモジュール導入に必要な作業は次の通りです。

  1. 取得済みGCMのAPI Keyを登録
  2. build.gradleの編集
  3. Backendサーバへのデバイス登録処理の実装

GCM API Keyを登録

Backendモジュールを作成したらGCMのAPI Keyを登録します。
API Keyは<backend>/src/main/webapp/WEB-INF/appengine-web.xmlに定義されているので、
これを取得済みのものに置き換えます。

<property name="gcm.api.key" value="YOUR_KEY_HERE"/>

YOUR_KEY_HEREを取得済みのAPI Keyに置換。

<property name="gcm.api.key" value="AIza..."/>

これでAPI Keyの登録は完了です。

build.gradleの編集

(この作業はAndroidStudio v0.8.2より後のバージョンでは不要になるかもしれません)
AndroidStudio v0.8.2でBackendモジュールとメインとなるappモジュールを関連づけすると、
ビルドで問題(preDexLibraryタスクでOutOfMemoryやIllegalArgumentException)が発生します。
これを回避するためにappからappengine-endpoints(-deps)ライブラリのコンパイル指定をコメントアウトします。

dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    compile 'com.android.support:appcompat-v7:19.0.+'
    compile 'com.google.android.gms:play-services:5.0.77'
//    appengine-endpoints(-deps)はBackendモジュールに含まれているため、appモジュールでの個別指定は不要
//    compile 'com.google.appengine:appengine-endpoints:1.9.1'
//    compile 'com.google.appengine:appengine-endpoints-deps:1.9.1'
    compile project(path: ':gcmbackend', configuration: 'android-endpoints')
}

Backendサーバへのデバイス登録処理の実装

下記のGcmRegistrationAsyncTaskクラスを取り込みます。
2.2. Registering devices with Google Cloud Messaging backend

GcmRegistrationAsyncTaskに定義されているSENDER_IDを自分のもの(GCM APIのProject Number)に置換します。
また、BackendサーバのURIを必要に応じて変更します。

  • Android Emulatorを使用している場合:http://10.0.2.2:8080/_ah/api/(変更なし)
  • Genymotionを使用している場合:http://10.0.3.2:8080/_ah/api/

Android Emulatorにおける10.0.2.2はホストループバックインターフェイスのエイリアスです(localhost)。
Genymotionでは10.0.3.2がこれにあたります。

全ての作業が終わったらBackendモジュールを実行し、ローカルサーバを起動します.
localhost:8080でGCMを送信するフォームが表示されます。
適当なActivityからGcmRegistrationAsyncTaskのexecuteを実行するとBackendサーバに端末のRegistrationIDが登録されます。
RegistrationID登録後にGCM送信フォームからテキストを送信すると端末にPush通知が届きます。

Androidアプリケーションの作成

GCMクライアントとなるAndroidアプリケーションを作成する場合はGoogleCloudMessaging APIの使用が推奨されています。

Google Play Serviceのセットアップ

アプリケーションの作成にはGoogle Play Serviceを使用します。
アプリケーションはGoogle Play ServiceのResourceにアクセスするため、単純に.jarを参照するだけでは動作しません。
AndroidStudioの場合はbuild.gradleのdependencyセクションに次を追記します。

dependencies {
    compile "com.google.android.gms:play-services:3.1.+"
}

GCMを使用するにはGoogle Play Service3.1以上である必要があります。

AndroidManifest.xmlの編集

次のPermissionを追加します。

  • com.google.android.c2dm.permission.RECEIVE: GCMサービスへの登録とメッセージ受信に必要
  • android.permission.INTERNET: 3rdPartyサーバへのRegistrationIDの登録に必要
  • android.permission.WAKE_LOCK: (optional)メッセージ受信時のWakeLock取得に必要
  • YourApplicationPackage + ".permission.C2D_MESSAGE": 他アプリからGCMへ登録されることやメッセージを横取りされるのを防ぐのに必要
  • com.google.android.c2dm.intent.RECEIVE: categoryに自アプリのパッケージ名を指定する。GCMメッセージ受信に必要
  • android.permission.GET_ACCOUNTS: GCMに必要なGoogleアカウント情報取得に必要(Android4.0.4以前で必要)
    a

    <!-- AndroidManifest.xml -->
    <manifest package="com.example">
        <uses-permission android:name="android.permission.INTERNET" />
        <uses-permission android:name="android.permission.WAKE_LOCK" />
        <uses-permission android:name="com.google.android.c2dm.permission.RECEIVE" />
        <!-- Android4.0.4以前をサポートする場合に必要 -->
        <uses-permission android:name="android.permission.GET_ACCOUNTS" />
        <!-- YourApplicationPackage + ".permission.C2D_MESSAGE" -->
        <permission android:name="com.example.permission.C2D_MESSAGE"
                android:protectionLevel="signature" />
        <uses-permission android:name="com.example.permission.C2D_MESSAGE" />
    

GCMの有効化

アプリケーションが初めてGCMを利用する前にGoogleCloudMessaging(API)のregister()メソッドを使ってGCMサービスへ登録する必要があります。
このメソッドはRegistrationIDを返します。参考:GoogleCloudMessaging

GCMへサービス登録する前にGoogle Play Serviceの状態をチェックします。
Google Play Serviceが古いバージョンである場合、Google Play Serviceの更新をユーザに促します。
アプリ起動中にGoogle Play Serviceがダウングレードされるケース等を考慮して、バージョンチェックはonResume()で行います。

@Override
protected void onResume() {
    super.onResume();
    try {
        PlayServiceUtil.updatePlayServiceIfNeeded(this, new DialogInterface.OnCancelListener() {
            @Override
            public void onCancel(DialogInterface dialog) {
                MyActivity.this.finish();
            }
        });
    } catch (PlayServiceUtil.PlayServiceException e) {
        // Play Serviceが使用できない致命的状態
        Log.e(TAG, "Play Service is not available.");
        this.finish();
    }
}

public static void updatePlayServiceIfNeeded(Activity activity, DialogInterface.OnCancelListener cancelListener) throws PlayServiceException {
    final int status = GooglePlayServicesUtil.isGooglePlayServicesAvailable(activity);
    switch (status) {
        case ConnectionResult.SUCCESS:
            return;
        case ConnectionResult.SERVICE_DISABLED:
        case ConnectionResult.SERVICE_INVALID:
        case ConnectionResult.SERVICE_MISSING:
        case ConnectionResult.SERVICE_VERSION_UPDATE_REQUIRED:
            Dialog dialog = GooglePlayServicesUtil.getErrorDialog(status, activity, 0);
            if (cancelListener != null) {
                dialog.setOnCancelListener(cancelListener);
            }
            dialog.show();
            return;
        default:
            throw new PlayServiceException("Play Service is not available. status=" + status);
    }
}

メッセージ送信

3rdPartyサーバ(以降”サーバ”)がメッセージ送信する時のシーケンス

  1. サーバはGCMにメッセージを送信
  2. GCMサーバは送信対象のデバイスがオフラインであればメッセージをキューイング/ストアする
  3. GCMサーバは送信対象のデバイスがオンラインになればメッセージを送信する
  4. デバイスはメッセージを受信すると配送すべきアプリケーションに向けてメッセージをブロードキャストする。
    配送されるのはアプリ固有のPermissionが設定されたBroadcastIntent。
  5. メッセージ処理が些末なものでない場合はPowerManager.WakeLockを取得してService上で実行する

メッセージ受信

デバイスがGCMメッセージを受信した時のシーケンス

  1. システムは、受信したメッセージからKey/Valueペアを展開
  2. システムは、com.google.android.c2dm.intent.RECEIVEのIntentとextraにKey/Valueデータを載せてアプリケーションに連携
  3. アプリケーションはIntentからKey/Valueを展開してデータを受け取る

参考サイト:
1. Google Cloud Messaging -android developers-

Portions of this page are modifications based on work created and shared by the Android Open Source Project and used according to terms described in the Creative Commons 2.5 Attribution License.
2014/05/21

Android+GradleなCI環境構築

ゴール:
 AWS EC2上にApache + Jenkinsの環境を構築。
 AndroidStudioで作成したプロジェクトをGithubへpush。
 GithubのWebhookでJenkinsにpush通知し、Gradleを使ってビルドさせます。

確認環境:
 クライアント:
  PC Mac OS X 10.9.2
  Gradle ver. 1.12
  Android Studio ver. 0.5.8
  Android Build tools gradle ver. 0.10.1
 サーバ:
  Amazon Linux AMI release 2014.03
  Apache/2.2.27(Unix) built:Apr 25 2014 22:26:04
  Jenkins ver.1.563-1.1
  JDK ver.1.7.0_55
  git ver. 1.8.3.1
  Gradle ver. 1.12
  Android SDK Build tools ver.19.1.0
  Android Build tools gradle ver. 0.10.1

AWS EC2インスタンス準備までは下記のサイトを参考に進めました。

参考:EC2にJenkinsによるCI環境を作成する | Developers.IO
http://dev.classmethod.jp/cloud/aws/jenkins_on_ec2/

EC2インスタンスタイプ:m1.small(試作程度なら micro でもOK)
EBSのボリュームサイズですが、初期の8GiBだとAndroidSDKのフルインストールが
ディスクフルとなって入りきらなかったので80GiBに増量して使用しています。

参考:ボリュームのストレージ領域を拡張する | AWS Documentation.
http://docs.aws.amazon.com/ja_jp/AWSEC2/latest/UserGuide/ebs-expand-volume.html

EC2インスタンスにユーザ"ec2-user”でSSH接続
$ ssh -i ./jenkins-key.pem ec2-user@54.xxx.xxx.xxx

●前準備

EC2 AmazonLinuxのタイムゾーンは、米国時間が初期設定なので日本時間に設定します。
$ sudo cp -P /usr/share/zoneinfo/Japan /etc/localtime
$ date

●JDKのインストール

ビルド環境構築のため、まずはJDKを導入。
AmazonLinuxは初期状態でJRE1.7.0_55が入っているようです(2014.5.19現在)
$java -version
java version "1.7.0_55"
OpenJDK Runtime Environment (amzn-2.4.7.1.40.amzn1-x86_64 u55-b13)
OpenJDK 64-Bit Server VM (build 24.51-b03, mixed mode)

JDKはrpmでインストールします。直接rpmファイルを取得するのが難しいので、
まず、Mac(ローカル)にサーバへインストールしたいJDKの.rpmをダウンロード。

DL先:Java SE Development Kit 7 Downloads | Oracle
http://www.oracle.com/technetwork/java/javase/downloads/jdk7-downloads-1880260.html
 => jdk-7u55-linux-x64.rpm

rpmファイルをscpでサーバに転送(最後のコロンを忘れずに)
$ scp -i ~/Documents/dev/jenkins-key.pem jdk-7u55-linux-x64.rpm ec2-user@54.xxx.xxx.xxx:

サーバのec2-userホームに.rpmファイルが転送されるのでこれをインストール。
$ sudo rpm -ivh jdk-7u55-linux-x64.rpm

インストールが完了したらJDK1.7.0_55に切り替え。
$ sudo alternatives --install /usr/bin/java java /usr/java/jdk1.7.0_55/bin/java 2000

切り替わったことを確認します。
$java -version
java version "1.7.0_55"
Java(TM) SE Runtime Environment (build 1.7.0_55-b13)
Java HotSpot(TM) 64-Bit Server VM (build 24.55-b03, mixed mode)

あとは環境変数を設定して、JDKの準備は完了。
$ export JAVA_HOME=/usr/java/jdk1.7.0_55/

●Apache+Jenkinsをインストール

とりあえずApacheをインストール。
$ sudo yum install httpd

次にJenkinsをインストール。
↓のコマンドを打ちたいところだけれど、これだとエラーがでました。
$ sudo yum install jenkins
> パッケージ jenkins は利用できません。

そのため、yumリポジトリにJenkinsを追加してからインストール。
$ wget -O /etc/yum.repos.d/jenkins.repo http://pkg.jenkins-ci.org/redhat/jenkins.repo
$ rpm --import http://pkg.jenkins-ci.org/redhat/jenkins-ci.org.key
$ sudo yum install jenkins

参考:RedHat Linux RPM packages for Jenkins | Jenkins CI
http://pkg.jenkins-ci.org/redhat/

インストールが終わったらJenkinsの設定を確認します。
$ sudo vim /etc/sysconfig/jenkins
Jenkinsのポート番号が8080であることを確認。
JENKINS_PORT=“8080"

念のため、8080ポートが使用済みでないか確認。
8080が未使用であれば問題ないので次へ(使用中なら別のポート番号を割り当ててください)
$ netstat -an | grep LISTEN
$ lsof -i -n -P

この時点で一度httpd, jenkinsサービスを起動して、アクセス確認してみます。
$ sudo service https start
$ sudo service jenkins start

うまくサービス開始できたら下記のURIにアクセス。
(Jenkinsのサービス起動には1分程かかる場合があります)
http://54.xxx.xxx.xxx:8080



今のURIでは不便なので、Jenkinsのドキュメントルートを変更します。
Jenkins設定ファイルのJENKINS_ARGSにドキュメントルートパスを指定します。
$ sudo vim /etc/sysconfig/jenkins
JENKINS_ARGS="--prefix=/jenkins”

これでJenkinsに下記のURIでアクセスできるようになります。
http://hogehoge:8080/jenkins

双方のサービスは自動起動するように設定しておきましょう。
$ sudo chkconfig httpd on
$ sudo chkconfig jenkins on

設定が反映されているか確認します。
$ /sbin/chkconfig --list | grep -e 'jenkins' -e 'httpd'

●Jenkinsユーザの設定

再度下記サイトを参考に、Jenkinsの初期設定(セキュリティ設定)を行います。
参考:EC2にJenkinsによるCI環境を作成する | Developers.IO
http://dev.classmethod.jp/cloud/aws/jenkins_on_ec2/

Jenkinsのホームディレクトリはパッケージ管理ソフトでインストールした場合、
/var/lib/jenkins になります。

●AndroidSDKのダウンロード

AndroidSDKをダウンロードします。
ダウンロードサイト:http://developer.android.com/sdk/index.html

次の手順でダウンロードリンクをコピー(2014.05.19現在ではr22.6.2が最新)
DOWNLOAD FOR OTHER PLATFORMS > SDK Tools Only > Linux32 > 64-bit

/usr/localにAndroidSDKを展開。
$ cd /usr/local/
$ sudo wget http://dl.google.com/android/android-sdk_r22.6.2-linux.tgz
$ sudo tar -xvzof android-sdk_r22.6.2-linux.tgz

ビルドに必要なツールを落とします。
$ sudo ./android update sdk --no-ui

↑のコマンドだと、エミュレータイメージ等もまとめてダウンロードするのでサイズが大きくなります。
$ sudo android update sdk -t platform -u
などとすれば、ダウンロードしたいモジュールを絞ることができます。
(今回は面倒だったのですべてダウンロードしました)

ダウンロードが完了したら環境変数を設定。
$ export ANDROID_HOME=/usr/local/android-sdk-linux/

JenkinsにもANDROID_HOMEのパスを追加します。
Jenkins > Jenkinsの管理 > システムの管理 > グローバル・プロパティ
 キー:ANDROID_HOME
 値:/usr/local/android-sdk-linux/

念のためAndroidSDKのビルドツールバージョンを確認しておきましょう。
$ ls $ANDROID_HOME/build-tools/

今回は19.1.0を使用しています。
Gradleでビルドする際のBuildToolsバージョンとあわせる必要があるので覚えておきます。

●Github連携(GitHub設定)

Githubへのpushをトリガに、JenkinsのワークスペースへgitリポジトリをCloneします。
GitHubにはpushをトリガに特定URIを叩く機構(Webhook)が用意されています。
Webhookを使って、「GitHubにpushされたらJenkinsでビルド」を実現します。

GitHubとの連携には鍵認証が必要です。
Jenkinsからのアクセスとなるので、Jenkins用のsshキーを作成。
$ cd /var/lib/jenkins
$ sudo mkdir .ssh
$ sudo chown jenkins .ssh
$ sudo -u jenkins -H ssh-keygen -t rsa -C jenkins@54.xxx.xxx.xxx
$ sudo chmod 755 ../.ssh

次に、公開鍵(id_rsa.pub)の内容をGitHubのSSH Keyとして登録。
GitHub > AccountSetting > SSH Keys > Add SSH Key
Titleは適当に。Keyは公開鍵の内容をペースト。

GitHubに鍵の登録ができたら接続テストをします。
$ sudo -u jenkins ssh -T git@github.com

問答の結果、次のメッセージが表示されれば成功。
Hi YukiMatsumura! You've successfully authenticated, but GitHub does not provide shell access.

これでGitHub連携の準備は完了です。

●GitHub連携(Jenkins設定)

JenkinsがWebhookできるように設定します。

まず、AmazonLinuxにgitをインストール。
$ sudo yum install git-core

次はJenkinsの設定。
Jenkins > Jenkinsの管理 > プラグインの管理 > [利用可能]タブ から
"GitHub Plugin”をインストールし、Jenkinsを再起動。

再起動が終わったら、Webhookを受信するJenkinsジョブを準備します。
"新規ジョブ作成”からジョブを作成します。
ジョブの種類は"フリースタイル・プロジェクトのビルド”とし、適当なジョブ名をつけて作成。

ジョブの設定項目は下記を参照。
GitHub project:GitHubリポジトリのURI(ブラウザで確認する際のURIでOK)
ソースコード管理:Gitを選択
 Repository URI:先ほどGitHub projectで入力したURIのhttps:スキームを"git:"に変更。
ビルド・トリガ:"Build when a change is pushed to GitHub"を選択

●GitHub連携(GitHub Webhook設定)

ブラウザからWebhook対象のGitHubリポジトリに移動し、
Settings > Webhooks & Services > Servicesの[Add service] > [Jenkins GitHub plugin]
Jenkins hook urlにはJenkinsサーバのルートに/github-webhook/を追加した文字列を指定します。
http://54.xxx.xxx.xxx:8080/jenkins/github-webhook/

設定後、GitHub側でWebhookURI編集画面にある[Test service]を押下すれば接続テストができます。
対象のJenkinsジョブにある"GitHub Hook Log”にアクセスログが残っていれば疎通確認OKです。

●AndroidStudioのプロジェクトをGitHubにpush

AndroidStudioとGitHubの連携については割愛します。
今回は無用な問題を避けるためにAndroidプロジェクトの
build.gradleに指定する各ビルドツールのバージョンを明示的に指定します。
・プロジェクトルートのbuild.gradle
buildscript {
    dependencies {
        classpath 'com.android.tools.build:gradle:0.10.1'

・モジュール毎のbuild.gradle
android {
    buildToolsVersion "19.1.0"
com.android.tools.build:gradleのバージョンが変わるとビルドが通らないことがよくあります。
buildToolsVersionについてはAmazonLinuxに展開したAndroidSDK側にも同じver.のものが必要です。

プロジェクトをGitHubにPushしたらJenkinsのジョブを確認。
新しいビルドがスケジューリングされているのがわかります。
ワークスペースにはGitHubにあるファイルがCloneされます。

●ビルド

Cloneしたソースをビルドします。
先ほど作成したジョブの”設定”からジョブを再編集します。

Gradle Wrapperを使ってビルドするために下記を設定します。
ビルド > [ビルド手順の追加 > “シェルの実行”
 シェルスクリプト:./gradlew build

これで、GitHubからリポジトリCloneした後にGradleによるビルドが実行されます。
今の状態でビルドしてみましょう。
# GitHubからClone済みであればジョブの"ビルド実行”からビルド開始できます

ビルド成功ならばOK。ビルド失敗ならば原因解析します。

ジョブ画面のビルド履歴からビルド結果の詳細が確認できます。
ビルド失敗した場合はビルド結果画面にある”コンソール出力”で失敗理由を確認します。

・失敗例1
What went wrong:
A problem occurred configuring project ':app'.
> SDK location not found. Define location with sdk.dir in the local.properties file or with an ANDROID_HOME environment variable.

環境変数”ANDROID_HOME”がjenkinsに設定されていません。
先述のグローバル・プロパティにANDROID_HOMEを設定することで解決します。

・失敗例2
* What went wrong:
Execution failed for task ':app:mergeDebugResources'.
> /var/lib/jenkins/jobs/hogehoge/workspace/build/exploded-aar/com.android.support/appcompat-v7/19.1.0/res/drawable-xxhdpi/abc_ic_voice_search.png: Error: Cannot run program "/usr/local/android-sdk-linux/build-tools/19.1.0/aapt": error=2, No such file or directory

aaptは32bitアプリケーションなので、32bit用ライブラリをインストールする必要があります。
まずは標準Cライブラリ(glibc)をインストール。
$ yum install glibc.i686

次に共有ライブラリの依存関係を調べます。
$ ldd /usr/local/android-sdk-linux/build-tools/19.1.0/aapt

手元の環境では下記の結果が得られたので、"not found”のライブラリをインストールしていきます。
linux-gate.so.1 =>  (0xf772a000)
librt.so.1 => /lib/librt.so.1 (0xf771b000)
libdl.so.2 => /lib/libdl.so.2 (0xf7716000)
libpthread.so.0 => /lib/libpthread.so.0 (0xf76fc000)
libz.so.1 => not found
libstdc++.so.6 => not found
libm.so.6 => /lib/libm.so.6 (0xf75de000)
libgcc_s.so.1 => not found
libc.so.6 => /lib/libc.so.6 (0xf7421000)
/lib/ld-linux.so.2 (0xf772b000)

libz.so.1のパッケージを検索、インストール。
$ yum whatprovies libz.so.1
 zlib-1.2.7-10.17.amzn1.i686 : The compression and decompression library
 リポジトリー        : amzn-main
 一致          :
 Provides    : libz.so.1
$ yum install zlib-1.2.7-10.17.amzn1.i686

libstdc++.soも同じく。
$ yum whatprovides libstdc++.so.6
 libstdc++44-4.4.6-4.81.amzn1.i686 : GNU Standard C++ Library
 リポジトリー        : amzn-main
 一致          :
 Provides    : libstdc++.so.6
$ yum install libstdc++44-4.4.6-4.81.amzn1.i686

libgcc_s.so.1も同じく。
$ yum whatprovides libgcc_s.so.1
 libgcc44-4.4.6-4.81.amzn1.i686 : GCC version 4.4 shared support library
 リポジトリー        : amzn-main
 一致          :
 Provides    : libgcc_s.so.1
$ yum install libgcc44-4.4.6-4.81.amzn1.i686

・その他失敗例
ビルドに失敗する要因は様々ですが、開発環境とJenkinsとで異なるGradleバージョンを使用している
ことが原因である可能性もあります。

・おわりに
今回の内容にはセキュリティの観点が含まれていません。
実運用する際にはAWS, GitHub, Jenkinsのセキュリティ設定にご注意ください。

以上。