Кроссплатформенная разработка мобильных приложений была очень популярна в свое время. Данный подход использовали большинство компаний во время становления мобильной отрасли. Основные причины задействовать кроссплатформенную разработку были просты — отсутствие профессиональных кадров на рынке, скорость и стоимость разработки. К сожалению, в большинстве случаев, данный подход не оправдал себя.
Но почему бы не дать ему второй шанс? Технологии шагнули вперед и теоретически мы можем получить очень качественный продукт. В данной статье мы рассмотрим на практике как разработать библиотеку для IOS/Android на языке Golang и посмотрим с какими ограничениями и проблемами мы столкнулись в процессе разработки.
Наша основная задача разработать SDK для сборки логов и крашей с мобильных приложений, при этом SDK должно подключаться и работать и с Android и с iOS приложениями. В тоже время библиотека должна взаимодействовать с основным сервисом LogPacker, который агрегирует и анализирует данные.
Мы решили использовать новые возможности языка Go для создания кроссплатформенной библиотеки. Во-первых, наше основное приложение написано на Go, и для нас было проще использовать данный язык и не привлекать Java/Objective-C разработчиков. Во-вторых, мы сэкономили время на разработку и попробовали старый подход с новыми возможностями.
Что такое gomobile?
Проект gomobile предоставляет разработчикам инструменты для сборки кода под мобильные платформы Android и iOS.
Сейчас существуют два способа интеграции Go в мобильную среду:
- Написание полноценного Go-приложения без UI.
- Генерация Java/Objective-C/Swift кода из Go.
Данная функция поддерживается начиная с Golang версии 1.5. Новая утилита gomobile помогает компилировать Go в мобильные приложения или собирать Java/Objective-C/Swift код.
Для начала выберем один из способов реализации. Первый способ нам не подходит из-за постановки задачи — нам нужна небольшая библиотека, а не отдельное приложение. Хотя способ очень интересный и перспективный благодаря скорости работы go приложений и минимизации потребления ресурсов мобильных устройств.
Мы выберем второй способ, и cгенерируем Java/Objective-C/Swift код из Go.
Настройка окружения
Для начала подготовим окружение для разработки. Нам нужен Go версии 1.5 или выше (чем выше — тем лучше, Go-сообщество вносит постоянные улучшения в Go Mobile).
Далее устанавливаем утилиту gomobile и библиотеку Android SDK. Начнем с установки gomobile:
go get golang.org/x/mobile/cmd/gomobile
Примечание: На OS X необходимо иметь установленный Xcode Command Line Tools.
Далее инициализируем gomobile, это может быть сделано один раз в любой рабочей директории:
gomobile init
Примечание: эта команда может занять несколько минут.
Для сборки Java-кода нам необходим Android SDK и установленная Java (OpenJDK достаточно).
Скачаем и распакуем Android SDK в домашнюю директорию, например ~/android-sdk, и выполним следующую команду для установки API версий:
~/android-sdk/tools/android sdk
Далее установите переменную окружающей среды:
export ANDROID_HOME=$HOME"/android-sdk"
Окружение для разработки и сборки библиотеки готово. Перейдем непосредственно к написанию кода, и посмотрим с какими ограничениями мы столкнулись.
Общий Go-код для Android и iOS
Один и тот же код может быть использован для дальнейшей компиляции под Android и iOS. Написание такого кроссплатформенного Go-кода имеет свои ограничения. В настоящее время мы можем использовать только некоторый набор типов данных. Разрабатывая приложение на Go, это необходимо учитывать. Рассмотрим более подробно поддерживаемые типы:
- int и float;
- string и boolean;
- byte[]. Текущая реализация не позволяет использовать []byte в качестве аргумента функции (https://golang.org/issues/12113);
- функция должна возвращать только поддерживаемые типы, может не возвращать результат, возвращать один тип или два типа, при том, что второй тип должен быть обязательно error;
- интерфейсы могут быть использованы, если при экспорте они будут использовать поддерживаемый тип;
- тип struct, только когда все поля соответствуют ограничениям.
Поэтому если тип не поддерживается командой gomobile bind, вы увидите подобную ошибку:
panic: unsupported basic seqType: uint64
Бесспорно набор поддерживаемых типов сильно ограничен, но для реализации нашего SDK этого вполне достаточно.
Сборка и импорт в Java/Objective-C/Swift
Gobind генерирует эквивалентный Go-коду код Java, Objective-C или Swift. К сожалению, gomobile не работает для Windows Phone и это нужно учитывать на этапе планирования.
Обычно gobind не используется напрямую, вместо этого код генерируется автоматически и оборачивается в пакет командой `gomobile bind`. Более подробно это описано тут golang.org/x/mobile/cmd/gomobile.
Рассмотрим некоторые команды и особенности процесса компиляции для каждой платформы.
Начнем с флага -target, который определяет платформу для генерации. Пример для Android:
gomobile bind --target=android .
Эта команда сгенерирует из текущего кода .aar файл. Импортировать данный файл в Android Studio очень просто:
- File > New > New Module > Import .JAR or .AAR package
- File > Project Structure > app -> Dependencies -> Add Module Dependency
- Добавить импорт: import go.logpackermobilesdk.Logpackermobilesdk
Примечание: В Java название пакета для импорта всегда начинается с go.
Похожая команда используется для сборки Objective-C/Swift кода:
gomobile bind --target=ios .
Будет создана папка .framework в текущей директории.
Это работает как для Objective-C так и для Swift. Переместите .framework папку в файловый браузер Xcode и добавьте импорт в проект:
#import "Logpackermobilesdk/Logpackermobilesdk.h"
Примечание: Go позволяет создавать не только SDK, но и компилировать само приложение в apk/ipa файлы из main.go файла, правда без поддержки нативного мобильного UI. Бесспорно это является очень интересным экспериментом Go-сообщества.
Использование подключенных пакетов
Gomobile bind автоматически создает функции getSomething(), setSomething(). Также все экспортируемые функции будут доступны публично.
Для примера использование нашей библиотеки в Android Studio:
import go.logpackermobilesdk.Logpackermobilesdk;
// ...
try {
client = Logpackermobilesdk.NewClient("https://logpacker.mywebsite.com", "dev", android.os.Build.MODEL);
msg = client.NewMessage();
msg.setMessage("Crash is here!");
// Use another optional setters for msg object
client.Send(msg); // Send will return Cluster response
} catch (Exception e) {
// Cannot connect to Cluster or validation error
}
Она же для Objective-C:
#import "ViewController.h"
#import "Logpackermobilesdk/Logpackermobilesdk.h"
@interface ViewController ()
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
GoLogpackermobilesdkClient *client;
NSError *error;
GoLogpackermobilesdkNewClient(@"https://logpacker.mywebsite.com", @"dev", [[UIDevice currentDevice] systemVersion], &client, &error);
GoLogpackermobilesdkMessage *msg;
msg = client.newMessage;
msg.message = @"Crash is here!";
// Use another optional setters for msg object
GoLogpackermobilesdkResult *result;
[client send:(msg) ret0_:(&result) error:(&error)];
}
Как видно из примеров выше, в итоге мы получили стандартные библиотеки. Конфигурация библиотек в приложении предельна проста и знакома разработчикам.
Заключение
Все понимают, что создание отдельных команд для разработки под каждую мобильную платформу — это не самое простое и дешевое удовольствие. Но для создания качественного продукта это необходимо на данном этапе времени. С другой стороны, нашу небольшую задачу мы смогли выполнить в рамках кроссплатформенной разработки и воспользовались всеми ее плюсами:
- Минимальные ресурсы на разработку.
- Скорость разработки.
- Простая поддержка решения в дальнейшем.
Минусом является то, что мы не смогли собрать библиотеку под Windows Phone, но об этом мы знали заранее.
Мы надеемся, что в скором времени появится простой способ написания полноценных приложений и SDK на языке Golang.
Вы можете ознакомиться с нашими наработками, склонировав наш репозиторий.
Автор: LogPacker