Как настроить проект LibGDX с Gradle, Google Play Services

Доброго времени суток.

Мы с товарищем занимаемся разработкой под Android уже несколько лет. Создавали игрушки на чистом Android, OpenGL, а также Unity3d. Главной проблемой первых двух технологий является непереносимость на разные мобильные платформы. Собственно, именно поэтому мы стали использовать Unity3d.

Это довольно интересная штука. Она сочетает в себе огромные возможности программирования при помощи мышки, а также программирования на скриптовом языке, смахивающем на C#. Так как мы Java разработчики, то хотелось написать что-то кроссплатформенное на Java. Выбор пал на LibGDX. Открыв мануал и скачав пару специальных сборщиков скелета проекта на LibGDX, начали работать.

В результате большую часть времени мы потратили не на программирование, но на настройку проекта, настройку gradle, а также добавление Google Play Services. В результате, набив шишки, решили написать эту статью.


Подготовка среды разработки


Для начала вам нужно скачать JDK 1.7. В своем проекте мы использовали Intellij Idea 14+ Community Edition. Ну и для мобильной разработки Android SDK. Также следует отметить, что рекомендуется использовать SDK Android 4.4W.2 (API 20). Далее нужно скачать сборщик проекта libGDX gdx-setup.jar.

Развертывание проекта


Для того, чтобы создать проект, разработчики libGDX предоставили очень удобную утилиту, в которой можно выбрать набор библиотек, которые вы будете использовать в своем проекте. В общем, запускаем gdx-setup.jar и заполняем все поля:

image

После нажатия generate создастся готовый тестовый проект на libGDX. Через Intellij Idea вызываем импорт и выбираем gradle.build в нашей директории проекта. Дальше через gradle таски можно запускать Android, Desktop, а также веб-приложения. Но вот только для дальнейшей разработки этот проект он не совсем пригоден. По каким-то непонятным причинам Android модуль в Idea остался без dependences и, соответственно, писать какой-то код в этом модуле не совсем удобно. Во-первых, если что-то писать на Android, то Idea не видит зависимостей и ничего не подсказывает, а во-вторых, если компилировать не через gradle, то посыпятся ошибки отсутствия собственно этих самых зависимостей. Мы долго копались и в итоге нашли правильную последовательность действий, чтобы собрать проект как надо.

Сборка проекта


Во-первых, создаем проект, как описывалось раннее. Затем в директории проекта запускаем команду
gradlew idea

Данная команда создаст правильные файлы проекта. Затем открываем проект *.ipr и смотрим на список модулей проекта. Индикатором того, что все зависимости применены, будет служить жирное выделение каждого модуля:

image

В принципе, уже можно работать с проектом. Для того, чтобы запустить Android приложение, надо добавить Debug / Run Configuration Andoid application со следующими настройками:

image

Аналогично создаем конфигурацию для Desktop приложения:

image

Для старта web приложения запускаем команду
gradlew html:superDev
после чего следуем инструкциям в логе.

Всё было бы хорошо, если бы мы не захотели добавить новых модулей в gradle проект. Не хотелось руками добавлять зависимости в настройки проекта, gradle ведь должен это делать сам. В общем, с этим вопросом мы также долго возились, потому что gradle долго отказывался видеть библиотеки Google Play Services.

Установка и настройка Google Play Services


Первым делом мы стали следовать инструкции Setting Up Google Play Services, в которой сказано следующее:

Добавить в конфигурацию build.gradle модуля Android:

dependencies {
    compile 'com.android.support:appcompat-v7:21.0.3'
    compile 'com.google.android.gms:play-services:6.5.87'
}

А также в AndroidManifest.xml следующее:

<meta-data android:name="com.google.android.gms.version" android:value="@integer/google_play_services_version" />

В результате после синхронизации Gradle мы наблюдаем вот такую ошибку:

 Could not find any version that matches com.google.android.gms:play-services:6+.
     Searched in the following locations:
         https://repo1.maven.org/maven2/com/google/android/gms/play-services/maven-metadata.xml
         https://repo1.maven.org/maven2/com/google/android/gms/play-services/
         https://oss.sonatype.org/content/repositories/snapshots/com/google/android/gms/play-services/maven-metadata.xml
         https://oss.sonatype.org/content/repositories/snapshots/com/google/android/gms/play-services/
         https://oss.sonatype.org/content/repositories/releases/com/google/android/gms/play-services/maven-metadata.xml
         https://oss.sonatype.org/content/repositories/releases/com/google/android/gms/play-services/

Получается, что данная библиотека не была найдена ни в maven репозитории, ни в других. Для того, чтобы исправить ситуацию, нужно в Android SDK Manager установить дополнительные библиотеки из пакета extras:

image

После установки всех библиотек проект собрался.

Далее в инструкции по установке были указаны ссылки на проект BaseGameUtils, в котором реализованы Helper классы для работы с Google Play Services. Тут всё довольно просто. Добавляем весь пакет в Android модуль, а в классе AndroidLauncher.java добавляем инициализацию GameHelper и наследуем его от интерфейса GameHelperListener.

public class AndroidLauncher extends AndroidApplication implements GameHelper.GameHelperListener {
    private GameHelper gameHelper;

	@Override
	protected void onCreate (Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);

        gameHelper = new GameHelper(this, GameHelper.CLIENT_ALL);
        gameHelper.setup(this);
    }
...


Здесь появляется еще одна проблема. Инстанциировали GameHelper мы в модуле Android, а вся разработка на libGDX проходит в модуле Core. Соответственно, надо придумать механизм, с помощью которого можно было бы вызывать методы GameHelper в Core. Для этого был придуман интерфейс IServices, который описывает всю работу с Google Play Service вызовами.

public interface IServices {
    public void signIn();

    public void showAchievements();
    public void showLeaderboard();

    public void addScore(final String scoreName, final Integer value);
    public Integer getScore(final String scoreName);

    public void unlockAchievement(final String achievementID);
    public boolean isAchievementUnlocked(final String achievementID);
}


Наследуем мы от этого интерфейса наш класс AndroidLauncher, реализуем все методы, а также сохраняем ссылку на него в статическом менеджере, доступ к которому есть во всем проекте.

public class AndroidLauncher extends AndroidApplication implements IServices, GameHelper.GameHelperListener {
    private GameHelper gameHelper;

	@Override
	protected void onCreate (Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
        gameHelper = new GameHelper(this, GameHelper.CLIENT_ALL);
		AchievementsManager.setPlayService(this);
        gameHelper.setup(this);
    }

    @Override
    public final void signIn() {
        try {
            runOnUiThread(new Runnable() {
                public final void run() {
                    gameHelper.beginUserInitiatedSignIn();
                }
            });
        } catch (final Exception ignored) {}
    }

    @Override
    public final void showAchievements() {
        try {
            runOnUiThread(new Runnable() {
                public final void run() {
                    startActivityForResult(Games.Achievements.getAchievementsIntent(gameHelper.mGoogleApiClient), REQUEST_ACHIEVEMENTS);
                }
            });
        } catch (final Exception ignored) {}
    }

    @Override
    public final void showLeaderboard() {
        try {
            runOnUiThread(new Runnable() {
                public final void run() {
                    startActivityForResult(Games.Leaderboards.getLeaderboardIntent(gameHelper.mGoogleApiClient, AchievementsManager.c_ScoreID), REQUEST_ACHIEVEMENTS);
                }
            });
        } catch (final Exception ignored) {}
    }

    @Override
    public final void addScore(final String scoreName, final Integer value) {
        try {
            Games.Leaderboards.submitScore(gameHelper.getApiClient(), scoreName, value);
        } catch (final Exception e) {
            e.printStackTrace();
        }
    }
    @Override
    public final void unlockAchievement(final String achievementID) {
        try {
            Games.Achievements.unlock(gameHelper.getApiClient(), achievementID);
        } catch (final Exception e) {
            e.printStackTrace();
        }
    }

    @Override
    protected final void onActivityResult(final int requestCode, final int resultCode, final Intent intent) {
        super.onActivityResult(requestCode, resultCode, intent);
        gameHelper.onActivityResult(requestCode, resultCode, intent);
    }
}

Следующий этап — это создание Google Play Services для вашего проекта в Google Developer Console. Всё, что нам нужно, это создать проект сервисов, в нем создать leaderboards и achievments, после чего добавить в константы проекта их id. Id самих сервисов нужно добавить в AndroidManifest:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.habrahabr.test"
    android:versionCode="5"
    android:versionName="1.0" >

    <uses-sdk android:minSdkVersion="9" android:targetSdkVersion="20" />

    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
    <uses-permission android:name="android.permission.INTERNET" />

    <application
        android:allowBackup="true"
        android:icon="@drawable/icon"
        android:label="@string/app_name"
        android:theme="@style/GdxTheme" >

        <meta-data android:name="com.google.android.gms.version"  android:value="@integer/google_play_services_version" />

        <meta-data android:name="com.google.android.gms.games.APP_ID" android:value="ID ваших сервисов" />
        <meta-data android:name="com.google.android.gms.appstate.APP_ID" android:value="ID ваших сервисов" />

        <activity
            android:name="com.gesoftware.figures.android.AndroidLauncher"
            android:label="@string/app_name" 
            android:screenOrientation="portrait"
            android:configChanges="keyboard|keyboardHidden|orientation|screenSize">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>
</manifest> 


Далее следует не забыть подписать проект ключом и выложить альфа релиз в Developer Console.

После этого сервисы всё равно не заработали. Причиной тому было отсутствие разрешений на API в консоле. Причем Google Play Game Management, Play Game Services и Google+ API были включены, но их было недостаточно. Пришлось добавлять еще Drive API, Drive SDK и Google Cloud Storage JSON API.

В результате мы смогли получить скелет проекта на LibGDX с встроенными в него Google Play Services. В следующей статье хотелось бы рассказать о самом проекте и способах построения архитектуры приложения с использованием библиотек libGDX
Ads
AdBlock has stolen the banner, but banners are not teeth — they will be back

More

Comments 6

    +1
    В результате большую часть времени мы потратили не на программирование, но на настройку проекта, настройку gradle, а также добавление Google Play Services.
    Ребята, я конечно понимаю, что незнакомый движок может быть сложноват, но почему человек, который настраивал проект, настолько неэффективен? Неужели написать приложение вышло быстрее, чем выполнить эти нехитрые манипуляции (с учетом того, что все это есть на офф. сайте)?
      –4
      Добавить 2 библиотеки в проект не проблема, проблема в том, чтобы добавить их в gradle конфигурацию. В мануале на офф. сайте ничего не написано про то, что в maven репозитории нет данных бибилиотек, и о том, что нужно их дополнительно устанавливать с помощью Android SDK Manager.
      В итоге получается что с помощью gradle нельзя просто взять и выкачать проект со всеми зависимостями и начать работать. Надо еще дополнительно что-то устанавливать, что я считаю не есть хорошо.
      Собственно поэтому и написали эту статью.
        +3
        И на закачку библиотеки через UI нажатием кнопки у вас ушло больше времени, чем на разработку?
        Не нужно ничего выкачивать было, только в gradle прописать одну строчку, как показано в мануале для разработчиков.
        ссылка
      –1
      Перед тем как тыкать в мануал (ссылку на который я привел в статье) попробуйте сами прописать эту строчку и собрать проект, а уже после удачной сборки что-то писать. Как было указано в статье, без установленых в Android SDK Manager библиотек вы получите ошибку
      Could not find any version that matches com.google.android.gms:play-services:6+.
           Searched in the following locations:
               https://repo1.maven.org/maven2/com/google/android/gms/play-services/maven-metadata.xml
      ...
      


        0
        Сталкивался с аналогичной проблемой и решение было на первой же строчке гугла:
        stackoverflow.com/a/17157227/1173794
          0
          Аргумент типа «сначала добейся»?
          Если копипастить по строчке и надеяться, что всё заработает само собой, то, конечно же, ничего работать скорее всего не будет. Нужно хотя бы понимать, что ты делаешь.

        Only users with full accounts can post comments. Log in, please.