概要
スクリプトからapkをアップロードする実験のメモ。
何ができるようになる?
- CircleCIなどと連携すれば今まで手作業でやっていたGooglePlayへのapkのアッロードがPullRequestベースで自動でできるようになる。
- アプリの説明文、スクリーンショットがGitで管理できるようになりそう。
- α、βテストがやりやすくなるかも。
- Hubotに、android deployとか話しかけるとproductionにアプリを公開とかもできそう。
Google APIs Client Libraryのインストール
色々と調べた結果、 PythonのGoogle APIs Client Libraryを使うのが一番簡単に実現できそうだったのでインストールする。インストールはpipで。
$ pip install google-api-python-client
サービスアカウントの登録
OAuth認証にサービスアカウントが必要になるので作成する。
1.DeveloperAPIとリンク
Developer Consoleの左メニュー「設定→APIアクセス」でDeveloperAPIをオンにする
https://play.google.com/apps/publish/#ApiAccessPlace
2.サービスアカウントの作成
APIアクセスページの下の方の「サービスアカウントの作成」をクリックすると以下のような画面が表示される。
3.Developer Consoleに移動
Developer ConsoleへのリンクからDeveloper Consoleへ移動し、「APIと認証」で「新しいクライアントIDの作成」をクリック。
すると以下の画面が表示されるので、サービスアカウントをチェックしクライアントIDを作成する。
作成が完了すると、以下の画面が表示され、Google Play Android Developer-1234abcd.p12というkeyファイルがダウンロードされる。
認証情報にサービスアカウントという項目(クライアントID、メールアドレス、証明書フィンガープリント)という項目が出来ていればOK。
サンプルコードの実行
Google Playにapkをアップロードしたり、紹介文を更新するサンプルコードがGitHubになるのでそれをとりあえずcloneしてみる。
$ git clone git@github.com:googlesamples/android-play-publisher-api.git
READMEのFirst request using OAuth2: Service accountsを参考に作業する。
1.basic_list_apks_service_account.pyを編集してサービスアカウントのメールアドレスを追加する
26行目の以下の部分を編集する。サービスアカウントのメールアドレスは、Developer Consoleの認証情報に表示されているもの。
SERVICE_ACCOUNT_EMAIL = (
'ENTER_YOUR_SERVICE_ACCOUNT_EMAIL_HERE@developer.gserviceaccount.com')
2.keyファイルの読み込み
38行目でkeyファイルを読み込んでいるので、ファイル名をサービスアカウントを作成した時にダウンロードしたkeyファイルに変更し(keyファイルの名前を変更してしまっても良い)、keyファイルを同一ディレクトリにコピーしておく。
3.サンプルを実行する
$ python basic_list_apks_service_account.py com.myapp.package
エラーがでる。
$ python basic_list_apks_service_account.py jp.horie1024.myapp
Traceback (most recent call last):
File "basic_list_apks_service_account.py", line 78, in <module>
main()
File "basic_list_apks_service_account.py", line 49, in main
scope='https://www.googleapis.com/auth/androidpublisher')
File "/usr/local/lib/python2.7/site-packages/oauth2client/util.py", line 132, in positional_wrapper
return wrapped(*args, **kwargs)
File "/usr/local/lib/python2.7/site-packages/oauth2client/client.py", line 1364, in __init__
_RequireCryptoOrDie()
File "/usr/local/lib/python2.7/site-packages/oauth2client/client.py", line 1318, in _RequireCryptoOrDie
raise CryptoUnavailableError('No crypto library available')
oauth2client.client.CryptoUnavailableError: No crypto library available
py-opensslが必要らしいのでpipでインストール
$ pip install PyOpenSSL
もう一度実行。
$ python basic_list_apks_service_account.py jp.horie1024.myapp
versionCode: 1, binary.sha1: b650430a19joihfel2lasiwbf38188d8d
うまくいった。
GooglePlayにスクリプトからapkをアップロードしてみる
サンプルコードには、サービスアカウントを使用してapkをGooglePlayへアップロードするスクリプトがなかったので幾つかのサンプルを参考に書いてみる。
cloneしてきたサンプルには、サービスアカウントを使用しないでapkをアップロードするサンプルとサービスアカウントを使用するサンプルがあるので二つを読みくらべてみる。二つのサンプルは、どちらもserviceオブジェクトを作成していて、認証部分の違いのみだった。なのでこれら二つのサンプルを組み合わてみる。
サービスアカウントを使用するサンプルをベースに以下のようにした。
#!/usr/bin/python
#
# Copyright 2014 Google Inc. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import argparse
from apiclient.discovery import build
import httplib2
from oauth2client import client
# aplha、beta、productionなどアップロード後の公開レベルの指定を追加
TRACK = 'alpha'
SERVICE_ACCOUNT_EMAIL = (
'ENTER_YOUR_SERVICE_ACCOUNT_EMAIL_HERE@developer.gserviceaccount.com')
argparser = argparse.ArgumentParser(add_help=False)
argparser.add_argument('package_name',
help='The package name. Example: com.android.sample')
# apk_fileへのパスを引数で受け取る処理追加
argparser.add_argument('apk_file',
nargs='?',
default='test.apk',
help='The path to the APK file to upload.')
def main():
f = file('key.p12', 'rb')
key = f.read()
f.close()
credentials = client.SignedJwtAssertionCredentials(
SERVICE_ACCOUNT_EMAIL,
key,
scope='https://www.googleapis.com/auth/androidpublisher')
http = httplib2.Http()
http = credentials.authorize(http)
service = build('androidpublisher', 'v2', http=http)
flags = argparser.parse_args()
package_name = flags.package_name
apk_file = flags.apk_file
# try以下はhttps://github.com/googlesamples/android-play-publisher-api/blob/master/v2/python/basic_upload_apks.pyのコードを使用
try:
edit_request = service.edits().insert(body={}, packageName=package_name)
result = edit_request.execute()
edit_id = result['id']
apk_response = service.edits().apks().upload(
editId=edit_id,
packageName=package_name,
media_body=apk_file).execute()
print 'Version code %d has been uploaded' % apk_response['versionCode']
track_response = service.edits().tracks().update(
editId=edit_id,
track=TRACK,
packageName=package_name,
body={u'versionCodes': [apk_response['versionCode']]}).execute()
print 'Track %s is set for version code(s) %s' % (
track_response['track'], str(track_response['versionCodes']))
commit_request = service.edits().commit(
editId=edit_id, packageName=package_name).execute()
print 'Edit "%s" has been committed' % (commit_request['id'])
except client.AccessTokenRefreshError:
print ('The credentials have been revoked or expired, please re-run the '
'application to re-authorize')
if __name__ == '__main__':
main()
実行
$ python upload_apks_service_account.py jp.horie1024.myapp /PATH/TO/APK/app-release.apk
エラーがでる。
$ python upload_apks_service_account.py jp.horie1024.myapp /PATH/TO/APK/app-release.apk
Version code 1 has been uploaded
Track alpha is set for version code(s) [1]
Traceback (most recent call last):
File "upload_apks_service_account.py", line 71, in <module>
main()
File "upload_apks_service_account.py", line 62, in main
editId=edit_id, packageName=package_name).execute()
File "/usr/local/lib/python2.7/site-packages/oauth2client/util.py", line 132, in positional_wrapper
return wrapped(*args, **kwargs)
File "/usr/local/lib/python2.7/site-packages/googleapiclient/http.py", line 723, in execute
raise HttpError(resp, content, uri=self.uri)
googleapiclient.errors.HttpError: <HttpError 401 when requesting https://www.googleapis.com/androidpublisher/v2/applications/jp.horie1024.myapp/edits/0455029384756893:commit?alt=json returned "The current user has insufficient permissions to perform the requested operation.">
サービスアカウントの権限が足りないので、DeveloperConsoleのユーザーアカウントと権限でサービスアカウントに権限を追加し、もう一度実行。
$ python upload_apks_service_account.py jp.horie1024.myapp /PATH/TO/APK/app-release.apk
Version code 1 has been uploaded
Track alpha is set for version code(s) [1]
Edit "128240713345872934" has been committed
うまくいった。
参考
- https://speakerdeck.com/gfx/androidapurifalseririsusitemasuka-number-potatotips
- http://www.slideshare.net/sakebook/google-play-developer-api
- https://developers.google.com/discovery/libraries
- http://stackoverflow.com/questions/27305867/google-api-access-using-service-account-oauth2client-client-cryptounavailableerr
- https://developers.google.com/android-publisher/api-ref/
- https://developers.google.com/android-publisher/api-ref/edits/insert
- https://developers.google.com/android-publisher/api-ref/edits#resource
追記
こちらのGradlePluginを使用するとより簡単にGooglePlayへのアップロードを自動化できます。
このプラグインについて紹介したスライドはこちらです。