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

в 8:31, , рубрики: game development, libgdx; gradle; android;, Разработка под android, метки:

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

Мы с товарищем занимаемся разработкой под 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

Автор: rannovr

Источник

Поделиться

* - обязательные к заполнению поля