Автоматизация публикации приложения в Google Play
Если у вас есть андроид приложение, которые вы собираетесь опубликовать в Google Play или оно уже опубликовано, а так же если вы его только разрабатываете, и оно находится в закрытом бета тестировании, а заказчику\тестерам периодически нужно собирать и передавать сборку руками, возможно лучше автоматизировать этот процесс
Вы можете самостоятельно разобраться с документацией на английском языке, но если процесс вызывает сложности или что-то не получается, надеюсь публикация окажется полезной
Перед началом работы нужно вручную опубликовать первую версию приложения
Настройка доступа
Откройте Google Play Developer Console и перейдите в меню Settings → API access
Консоль нужно связать c Google API проектом. Если у вас нет проекта, то на данный момент из интерфейса будет доступна только кнопка Create new project
Если же есть, то будет доступен список этих проектов. Кнопка link понятное дело их связывает
Но давайте рассмотрим пример с созданием нового проекта. Его можно создать из Google API Console или прямо из Google Play Developer Console, который у вас уже открыт, нажмите кнопку Create new project
Если вы первый раз создаете Google API проект, появится popup-окошко, тут Accept All
Отлично, теперь у вас есть проект и service account, который в данном случае создается автоматически
Сейчас нужно разрешить этому аккаунту работать с Google Play и дать ему роль. Это так же можно сделать прямо отсюда, нажмите Grant access. Вас перекинет в меню User accounts & right (видно на заднем плане) и откроется popup-окошко, где email и остальные обязательные поля уже будут заполнены. Нажмите Add user
Сейчас вы видите, что ваш пользователь успешно добавлен
Теперь нужно сгенерировать пару публичный и приватный ключи, чтобы можно было работать с библиотеками и публиковать новые версии приложения. Для этого откройте список проектов в Google API Console и кликните по нужному, по умолчанию он называется Google Play Android Developer
Далее нажмите пункт меню Credentials → Create credentials, выберите Service account key
Выберите из списка Compute Engine default service account и перекиньте radio button на P12. Нажмите Create
С настройками все, пара публичный и приватный ключи с названием Google Play Android Developer-%кусочек id%.p12 была сохранена на компе
Приступим к программированию
Сейчас Google предоставляет библиотеки на java и python для работы с Google Play Developer API. Мы рассмотрим вариант на java, для этого скачайте zip-архив с библиотеками и примерами
Откройте вашу IDE и создайте проект, свой я назвал ProductionManager, подключите следующие библиотеки:
- google-api-client-1.19.0.jar
- google-api-services-androidpublisher-v2-rev20141111–1.19.0.jar
- google-http-client-1.19.0.jar
- google-http-client-jackson2–1.19.0.jar
- google-oauth-client-1.19.0.jar
- jackson-core-2.1.3.jar
Скопируйте файл Google Play Android Developer-%кусочек id%.p12 в resource папку вашего проекта, я его переименовал чтобы не было пробелов, кажется у меня было исключение при попытке его прочитать. Если вы будете держать исходники этого проекта в VCS куда есть доступ у многих людей, наверное лучше хранить файл на сервере непрерывной интеграции, тут на ваше усмотрение.
Перед сборкой и соответственно публикацией приложения я делаю запрос, чтобы узнать последнюю версию кода (versionCode) и обновить ее, потому что мне нравится чтобы они шли в арифметической прогрессии с шагом 1(те просто 1, 2, 3…), вы можете просто подставить buildNumber из CI сервера или revesionNumber из вашей VCS, тоже на ваше усмотрение
private Edits getApplicationEdits() throws Exception {
String applicationName = "ApplicationName";
String serviceAccountId = "и-го-го@developer.gserviceaccount.com"
HttpTransport httpTransport = GoogleNetHttpTransport.newTrustedTransport();
JsonFactory jsonFactory = JacksonFactory.getDefaultInstance();
KeyStore keyStore = SecurityUtils.getPkcs12KeyStore();
InputStream inputStream = ProductionManager.class.getResourceAsStream("/resources/key.p12");
PrivateKey privateKey = SecurityUtils.loadPrivateKeyFromKeyStore(keyStore, inputStream, "notasecret", "privatekey", "notasecret");
inputStream.close();
GoogleCredential credential = new GoogleCredential
.Builder()
.setTransport(httpTransport)
.setJsonFactory(jsonFactory)
.setServiceAccountId(serviceAccountId)
.setServiceAccountScopes(Collections.singleton(AndroidPublisherScopes.ANDROIDPUBLISHER))
.setServiceAccountPrivateKey(privateKey)
.build();
AndroidPublisher androidPublisher = new AndroidPublisher
.Builder(httpTransport, jsonFactory, credential)
.setApplicationName(applicationName)
.build();
return androidPublisher.edits();
}
private void updateVersionCode() throws Exception {
String packageName = "com.package.name";
Edits edits = getApplicationEdits();
String editId = edits
.insert(packageName, null)
.execute()
.getId();
ApksListResponse apksResponse = edits
.apks()
.list(packageName, editId)
.execute();
List versions = new ArrayList();
List apks = apksResponse.getApks();
if (apks == null) {
throw new Exception("responsed list of apks is null");
}
for (Apk apk : apks) {
versions.add(apk.getVersionCode());
}
if (versions.isEmpty()) {
throw new Exception("previous versions are not detected");
}
int lastVersionCode = Collections.max(versions);
if (lastVersionCode == 0) {
throw new Exception("version is 0");
}
//TODO update version code
//++lastVersionCode
}
private void publishApplication() throws Exception {
String packageName = "com.package.name";
String track = "beta";//release
String setupFilePath = "/path/to/setup/file/app.apk";
Edits edits = getApplicationEdits();
String editId = edits
.insert(packageName, null)
.execute()
.getId();
FileContent mediaContent = new FileContent("application/vnd.android.package-archive", new File(setupFilePath));
Upload uploadRequest = edits
.apks()
.upload(packageName, editId, mediaContent);
Apk apk = uploadRequest.execute();
List versions = new ArrayList<>();
versions.add(apk.getVersionCode());
edits
.tracks()
.update(packageName, editId, track, new Track().setVersionCodes(versions))
.execute();
edits
.commit(packageName, editId)
.execute();
}
Скомпилируйте executable jar. Теперь нужно настроить создание инсталляционного файла и его публикацию на вашем CI сервере, я использую TeamCity. Получается, у нас будет 4 build steps:
- Обновление versionСode. Запустите jar-файл с параметром, который вы обработаете и вызовите метод updateVersionCode (). Вот так это выглядит на TeamCity
- Обновление versionName
- Генерация apk. Можно командной строкой, можно выбрать специальный step, есть gradle и IntelliJ IDEA, во втором случае нужно указать имя artifact-а
- Публикация приложения. Так же запускаете jar-файл с другим параметром и вызываете метод publishApplication ()
Спасибо за внимание