Однажды возникло желание изучить для своих скромных нужд Lua. Но просто прочесть спецификации и примеры не интересно, и давно была мысль написать свою логическую игру под Android, начались поиски подходящего фреймворка для комфортной работы.
После недолгого просмотра гугла выделились 2 основных кандидата: Corona SDK и LÖVE. Corona SDK обладает, с моей точки зрения, несомненными преимуществами: поддержка, хорошая документация, легкая интеграция разнообразных магазинов/реклам/социальных сетей (нужное подчеркнуть). Несмотря на это, сам SDK платный, нет версии под Linux. Версия Starter обладает рядом ограничений.
После Corona SDK я взялся за внимательное рассмотрение LÖVE. Первым делом подкупила надпись на стартовой странице:
Есть довольно хорошая документация даже на русском языке. Фреймфорк легок в установке. Как написать игру, используя LÖVE пользователь yegorf1 писал здесь и продолжил здесь. Так, неспешно изучая возможности фреймворка, я написал прототип своего приложения. И здесь началось самое интересное.
Как запустить приложение под андроид, чтобы наконец проверить свое «чудо» на любимом смартфоне?
Поиск ответа на этот вопрос навел меня на проект love-android-sdl2, разработчиком которого является Martin Felis. Как пишет автор, проект является портом LÖVE под андроид. По сути это порт Lua на SDL 2.0 под андроид.
На выходе мы имеем .apk-файл, который же можно залить в телефон и наконец потестировать! Как собрать релиз и подписать его, можно подробно почитать здесь.
Итак, ответ на первый вопрос получен. Конечно, сделать быстрое или очень экономное приложение вряд ли получится, но для быстрого протот��пирования на Lua или легковесной игры самое то. Почти пустой .apk-файл сразу весит около 5 мб, а основное приложение в ассетах может повергнуть эстетов Java или С++ в легкий шок, хотя насчет последних я не уверен. Можно попробовать убрать ненужные библиотеки, но это уже тема других экспериментов.
Когда приложение стало приобретать все более законченные черты, пришла пора задуматься о возможной монетизации. Конечно, есть вариант совсем для ленивых. Выставить приложение за фиксированную цену и ждать у моря на Мальдивах легкого бриза. Но я себе такого пока позволить не могу, а учитывая таргетирование на андроид, я подумал, что надо так или иначе встроить рекламу. Интеграцией с рекламным сервисом AdMob я никогда не занимался. Учитывая специфику получившегося «бутерброда» из библиотек, мне стало еще интереснее.
Как интегрировать AdMob в свое приложение?
Поскольку официальная справка (en и рус) предлагает использовать в этом процесс Eclipse, стало очевидно, что:
Первая серия экспериментов с использованием официальной справки по интеграции AdMob не привела к успеху. Я обратился за помощью к разработчику проекта, но он ответил, что еще не пробовал добавлять AdMob в свой проект, и что ему бы было тоже интересно, как это сделать.
Ответ на второй и больше всего волнующий меня вопрос был найден. Таким способом мне удалось «подружить» LÖVE, Android и AdMob. Моя игра почти закончена, я надеюсь на скорый релиз. Happy end.
После недолгого просмотра гугла выделились 2 основных кандидата: Corona SDK и LÖVE. Corona SDK обладает, с моей точки зрения, несомненными преимуществами: поддержка, хорошая документация, легкая интеграция разнообразных магазинов/реклам/социальных сетей (нужное подчеркнуть). Несмотря на это, сам SDK платный, нет версии под Linux. Версия Starter обладает рядом ограничений.
После Corona SDK я взялся за внимательное рассмотрение LÖVE. Первым делом подкупила надпись на стартовой странице:
It's free, open-source, and works on Windows, Mac OS X and Linux.
LÖVE is licensed under the liberal zlib/libpng license. That means you can use it freely for any purpose — including commercial ones.
Есть довольно хорошая документация даже на русском языке. Фреймфорк легок в установке. Как написать игру, используя LÖVE пользователь yegorf1 писал здесь и продолжил здесь. Так, неспешно изучая возможности фреймворка, я написал прототип своего приложения. И здесь началось самое интересное.
Вопрос №1
Как запустить приложение под андроид, чтобы наконец проверить свое «чудо» на любимом смартфоне?
Поиск ответа на этот вопрос навел меня на проект love-android-sdl2, разработчиком которого является Martin Felis. Как пишет автор, проект является портом LÖVE под андроид. По сути это порт Lua на SDL 2.0 под андроид.
- Пакуем свое приложение в zip-архив и переименовываем его в game.love
- Коприуем архив в папку assets проекта.
- Собираем .apk-файл согласно инструкциям для Linux, Windows, Mac OS X. Процесс подробно описан у автора, если кратко его описать, то это несколько шагов:
- Установка Android SDK, Android NDK
- Утановка Android SDK Platoform-tools, Android SDK Built-tools, Android 4.4.2 (API 19) and the Android Support Library через SDK Manager
- Запуск сборки в директории с проектом. Сначала ndk-build, потом ant debug.
На выходе мы имеем .apk-файл, который же можно залить в телефон и наконец потестировать! Как собрать релиз и подписать его, можно подробно почитать здесь.
Итак, ответ на первый вопрос получен. Конечно, сделать быстрое или очень экономное приложение вряд ли получится, но для быстрого протот��пирования на Lua или легковесной игры самое то. Почти пустой .apk-файл сразу весит около 5 мб, а основное приложение в ассетах может повергнуть эстетов Java или С++ в легкий шок, хотя насчет последних я не уверен. Можно попробовать убрать ненужные библиотеки, но это уже тема других экспериментов.
Когда приложение стало приобретать все более законченные черты, пришла пора задуматься о возможной монетизации. Конечно, есть вариант совсем для ленивых. Выставить приложение за фиксированную цену и ждать у моря на Мальдивах легкого бриза. Но я себе такого пока позволить не могу, а учитывая таргетирование на андроид, я подумал, что надо так или иначе встроить рекламу. Интеграцией с рекламным сервисом AdMob я никогда не занимался. Учитывая специфику получившегося «бутерброда» из библиотек, мне стало еще интереснее.
Вопрос №2
Как интегрировать AdMob в свое приложение?
Поскольку официальная справка (en и рус) предлагает использовать в этом процесс Eclipse, стало очевидно, что:
- Необходимо собрать приложение в Eclipse. Эта часть в основном полезна для новичков. Для этого скачиваем чистый проект love-android-sdl2.
git clone git@bitbucket.org:MartinFelis/love-android-sdl2.git - Открываем Eclipse (я использую из ADT Bundle). Создаем новый workspace и добавляем наш проект File → New → Project… → Android → Android Project from Existing Code.

Далее указываем путь до папки с проектом. Должно определиться 2 проекта: love-android-sdl2 и SDLActivity. Жмем Finish. - Заходим в свойства проекта SDLActivity. Левой кнопкой мыши жмем на проект, выбираем Properties. Далее Android и ставим галочку Is Library. Жмем OK.

- Заходим в свойства проекта love-android-sdl2. Java Build Path → вкладка Libraries → Add JARs… → находим SDLActivity/bin/sdlactivity.jar.

- Затем идем во вкладку Builders и снимаем галочку напротив [Löve] Generate Internal Scripts.
- Нажимаем кнопку Run As… → Android Application
. - Ждем пока соберется проект, и Eclipse попросит нас подключить устройство или запустить love-android-sdl2.apk на эмуляторе.
Первая серия экспериментов с использованием официальной справки по интеграции AdMob не привела к успеху. Я обратился за помощью к разработчику проекта, но он ответил, что еще не пробовал добавлять AdMob в свой проект, и что ему бы было тоже интересно, как это сделать.
- Следуем инструкциям стандартной справки начиная с раздела 1. Внедрение библиотеки сервисов Google Play в проект. Единственное оговорюсь, что проект google-play-services_lib необходимо добавить сначала из sdk/extras/google/google_play_services/libproject/google-play-services_lib.
- Дальше можно сделать Project → Clean… → Clean all project → OK и перезапустить сборку.
- Открываем файл love-android-sdl2/src/org.love2d.android/GameActivity.java
- Дописываем необходимый код.
Листинг GameActivity.javapackage org.love2d.android; import com.google.android.gms.ads.*; // импортируем библиотеки для рекламы import org.libsdl.app.SDLActivity; import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.HttpURLConnection; import java.net.URL; import android.app.DownloadManager; import android.app.ProgressDialog; import android.content.Context; import android.content.DialogInterface; import android.content.Intent; import android.net.Uri; import android.os.AsyncTask; import android.os.Build; import android.os.Bundle; import android.os.Environment; import android.os.Handler; import android.os.PowerManager; import android.os.ResultReceiver; import android.util.Log; import android.util.DisplayMetrics; import android.widget.RelativeLayout; import android.widget.Toast; public class GameActivity extends SDLActivity { private static DisplayMetrics metrics = new DisplayMetrics(); private static String gamePath = ""; private static Context context; private AdView adView; @Override protected void onCreate(Bundle savedInstanceState) { Log.d("GameActivity", "started"); context = this.getApplicationContext(); Uri game = this.getIntent().getData(); if (game != null) { if (game.getScheme().equals ("file")) { gamePath = game.getPath(); } else { copyGameToCache (game); } Log.d("GameActivity", "Selected the file: " + getGamePath()); } super.onCreate(savedInstanceState); getWindowManager().getDefaultDisplay().getMetrics(metrics); // Создаем экземпляр AdView adView = new AdView(mSingleton); adView.setAdSize(AdSize.BANNER); // задаем размер adView.setAdUnitId("ca-app-pub-1209995634500922/8885931497"); // прописывам id приложения // Задаем параметры отображения RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams( RelativeLayout.LayoutParams.WRAP_CONTENT, RelativeLayout.LayoutParams.WRAP_CONTENT); params.addRule(RelativeLayout.ALIGN_PARENT_TOP); params.addRule(RelativeLayout.CENTER_HORIZONTAL); AdRequest adRequest = new AdRequest.Builder().build(); adView.loadAd(adRequest); mLayout.addView(adView, params); } public static String getGamePath() { Log.d ("GameActivity", "called getGamePath(), game path = " + gamePath); return gamePath; } public static DisplayMetrics getMetrics() { return metrics; } public static void openURL (String url) { Log.d ("GameActivity", "opening url = " + url); Intent i = new Intent(Intent.ACTION_VIEW); i.setData(Uri.parse(url)); i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); context.startActivity(i); } void copyGameToCache (Uri sourceuri) { String destinationFilename = this.getCacheDir().getPath()+"/downloaded.love"; gamePath = destinationFilename; BufferedOutputStream bos = null; try { bos = new BufferedOutputStream(new FileOutputStream(destinationFilename, false)); } catch (IOException e) { Log.d ("GameActivity", "Could not open destination file:" + e.getMessage()); } int chunk_read = 0; int bytes_written = 0; BufferedInputStream bis = null; if (sourceuri.getScheme().equals("content")) { try { bis = new BufferedInputStream(getContentResolver().openInputStream(sourceuri)); } catch (IOException e) { Log.d ("GameActivity", "Could not open game file:" + e.getMessage()); } } else { Log.d ("GameActivity", "Unsupported scheme: " + sourceuri.getScheme()); } if (bis != null) { // actual copying try { byte[] buf = new byte[1024]; chunk_read = bis.read(buf); do { bos.write(buf, 0, chunk_read); bytes_written += chunk_read; chunk_read = bis.read(buf); } while(chunk_read != -1); } catch (IOException e) { Log.d ("GameActivity", "Copying failed:" + e.getMessage()); } } // close streams try { if (bis != null) bis.close(); if (bos != null) bos.close(); } catch (IOException e) { Log.d ("GameActivity", "Copying failed: " + e.getMessage()); } Log.d("GameActivity", "Copied " + bytes_written + " bytes"); } }
- Пересобираем наше приложение, запускаем, немного ждем и видим сверху рекламу!

Ответ на второй и больше всего волнующий меня вопрос был найден. Таким способом мне удалось «подружить» LÖVE, Android и AdMob. Моя игра почти закончена, я надеюсь на скорый релиз. Happy end.
