Язык программирования Go стал настоящим открытием для разработчиков инструментов для системного администрирования и DevOps благодаря комбинации возможностей низкоуровневой разработки (и в этом он подобен C) и поддержке автоматической сборки мусора, исключению прямой работы с указателями, наличию конкуретной многозадачности (goroutines) и возможности компиляции непосредственно в исполняемый образ. Постепенно Go начал использоваться для других целей: создание веб-приложений, разработка для микроконтроллеров. Почему бы не использовать все его возможности для создания мобильных приложений? В статье мы обсудим некоторые подходы к разработке приложений на Go для мобильных устройств.

Важно отметить, что архитектура мобильных операционных систем разделяет реализацию интерфейса от среды исполнения приложения и это позволяет описывать интерфейс пользователя на любой технологии (не обязательно на Java/Kotlin для Android). Однако важно помнить, что точка входа в приложение и стартовый код в любом случае должны быть созданы на соответствующей технологии (например, код на Dart/Flutter запускается из Java-кода, который подготавливает соответствующую поверхность для отображений и выполняет инициализацию необходимых сервисов из MainActivity), а сборка выполняется через Gradle, как единое приложение (JVM-часть + двоичный код, как результат компиляции исходных текстов). Аналогично с iOS, в этом случае сборку выполняет XCode и точка входа описывается как ViewController, который определен на языке Swift или ObjectiveC. Поэтому для разработки приложения на Go нужно обеспечить аналогичный уровень интеграции и сгенерировать обертку для запуска скомпилированного кода внутри привычной для платформы среды исполнения.

Одной из библиотек для создания мобильных приложений на Go является gomobile. С помощью gomobile можно создавать как библиотеки, так и полноценные приложения (упакованные в формат apk / ipa). Также поддерживается сборка приложения для OpenAL для работы с аудио с использованием Go.

Установка утилиты командной строки gomobile выполняется из официального репозитория через go install:

go install golang.org/x/mobile/cmd/gomobile@latest
export PATH=~/go/bin:$PATH
gomobile init

Пример приложения можно скачать из пакета basic (исходные тексты), для сборки примера под соответствующую платформу будет использоваться команда:

gomobile build [-target android|ios] [-androidapi <version>] [-o filename] package

Соберем простой пример:

go mod init example.com/m
go mod tidy
go get -d golang.org/x/mobile/example/basic
gomobile build -target android -androidapi 19 golang.org/x/mobile/example/basic

Для успешной сборки должен быть установлен компонент NDK (Native Development Kit) для Android SDK. Результатом сборки будет файл apk, который также может быть автоматически установлен на устройство при замене команды gomobile build на gomobile install. Также может быть собрана библиотека для подключения к нативному приложению (в Android будет собран как aar, который может быть подключен через gradle implementation, в iOS - как фреймворк, на других платформах будет скомпилирован в динамическую библиотеку). После запуска примера приложение отображает треугольник на EGL и циклически изменяет его цвет.

Пример приложения на gomobile
Пример приложения на gomobile

Приложение регистрируется как аргумент в функции app.Main (app из golang.org/x/mobile/app) и получает доступ к EGL-контексту для рисования и потоку событий (жизненный цикл приложения, взаимодействия пользователя с интерфейсом, отрисовки экрана). Основное приложение может выглядеть следующим образом:

app.Main(func(a app.App) {
	var glctx gl.Context
	var sz size.Event
    for e := range a.Events() {
	   switch e := a.Filter(e).(type) {
       //... обработка сообщений
       }
    }
}

Наиболее важные типы сообщений:

  • lifecycle.Event - события жизненного цикла, например отображение и скрытие Activity / ViewController

  • size.Event - событие изменение размера (например, изменение ориентации экрана)

  • paint.Event - событие отрисовки экрана (vsync, в случае с Android отправляется из Choreographer)

  • touch.Event - событие нажатия на экран

  • key.Event - событие от клавиатуры

  • mouse.Event - событие от мыши (например, может быть на MacOS)

Сообщения могут быть получены от среды исполнения, а также отправлены через объект app.App (функция send).

Событие в lifecycle.Event может быть извлечено через e.Crosses(lifecycle.StageVisible) и при получении сообщения lifecycle.CrossOn нужно выполнить инициализацию контекста EGL для построений, lifecycle.CrossOff освободить контекст.

При разработке приложений интерфейс EGL представляется непосредственно через методы gl.Context и для построения графических примитивов нужно определить фрагментный и вершинный шейдеры и сконфигурировать буферы для значений, передаваемых в шейдеры. Например, для построения прямоугольника можно определить вершинный шейдер подобным образом:

#version 100

uniform vec2 offset;
attribute vec4 position;

void main() {
//координатная сетка от (-1,-1) до (1,1)
	vec4 offset4 = vec4(2.0*offset.x-1.0, 1.0-2.0*offset.y, 0, 0);
	gl_Position = position + offset4;
}

Фрагментный шейдер может использовать координаты фрагмента (gl_Coord), но в простом варианте он может определять одноцветную фигуру:

#version 100

precision mediump float;
uniform vec4 color;

void main() {
	gl_FragColor = color;
}

Для инициализации контекста будем использовать вспомогательные структуры из golang.org/x/mobile/exp/gl/glutil. На событии CrossOn извлечем контекст EGL:

glctx, _ = e.DrawContext.(gl.Context)
program, err = glutil.CreateProgram(glctx, vertexShader, fragmentShader)

Для построения геометрической фигуры создадим gl.ARRAY_BUFFER и загрузим туда данные о координатах точек, группами по 3 значения с плавающей точкой x, y, z через f32.Bytes(binary.LittleEndian, ...). f32 импортируется из golang.org/x/mobile/exp/f32.

Для передачи параметров в шейдеры будем использовать glctx.GetAttributeLocation (для передачи координат точек через буфер) и glctx.GetUniformLocation (для передачи значений цвета и смещения). 

Построение сцены выполняется обычным для EGL образом:

  • очистка сцены: glctx.ClearColor(r, g, b, alpha)

  • подключение программы: glctx.UseProgram(program)

  • заполнение буферов (glctx.BindBuffer) и значений (glctx.UniformNf, где N - 1, 2, 3 или 4)

  • построение изображения: glctx.DrawArrays(gl.Triangles, 0, vertexCount)

С использованием шейдеров и возможностей EGL можно как симулировать привычный интерфейс пользователя, так и создавать сложные сцены (например, с поддержкой 3d-объектов, света, камеры и других вычислительных возможностей фрагментного шейдера). При этом будут доступны все возможности стандартных пакетов Go (например, для работы с сетью, математики, криптографии и др.), а также любых подключаемых библиотек Go. Также, кроме поддержки EGL и событий жизненного цикла, доступен доступ к assets (например, для построения объектов с использованием растровых текстур и спрайтов через golang.org/x/mobile/exp/sprite/glsprite). Экспериментально поддерживается воспроизведение и обработка звука (golang.org/x/mobile/exp/audio/al), вывод количества кадров в секунду (построение растровых цифр в golang.org/x/mobile/exp/app/debug/fps.go), поддержка шрифтов (на платформах Android / iOS / MacOS и Linux) в golang.org/x/mobile/exp/font, а также извлечение данных от акселерометра, магнетометра и гироскопа (golang.org/x/mobile/exp/sensor). 

Поскольку скомпилированный код Go будет выполняться как нативное приложение и имеет прямой доступ к EGL, аудиопотокам, информации с сенсоров и событий пользовательского интерфейса, библиотека GoMobile может использоваться как для разработки приложений с имитацией интерфейсов Material Design / iOS Human Interface Guidelines, так и для создания мультимедийных и игровых приложений с возможностью переиспользования Go-библиотек.

На этом все. Также хочу пригласить всех желающих на бесплатный урок курса Golang Developer по теме: "Тестирование в Go". Зарегистрироваться на урок и узнать о курсе подробнее можно по ссылке ниже.

Комментарии (9)


  1. s60
    08.11.2022 19:08
    -1

    какую IDE для Go используешь ?


    1. dmitriizolotov Автор
      08.11.2022 22:07
      +2

      VSCode с официальным плагином для Go


    1. s60
      10.11.2022 11:32
      +1

      а чо минусаторы то возбудились…?


  1. savostin
    08.11.2022 20:25
    +4

    Странно, что в статье нет ни одного скриншота приложения...


    1. dmitriizolotov Автор
      08.11.2022 22:06

      Спасибо, упустил этот момент, добавил скриншот.


      1. savostin
        08.11.2022 22:34
        +5

        Вот теперь понятно. Но... мда.


  1. Tuxman
    09.11.2022 05:08
    +1

    Я то думал, сейчас будет как на flutter, только на языке Go, а тут только треугольнички рисовать и никаких виджетов, ни нативных платформенных, ни библиотекой нарисованных.


    1. DreamingKitten
      09.11.2022 09:39
      +2

      С этим вам поможет fyne.io


  1. rabid_otter
    10.11.2022 08:28
    +1

    Хм, честно говоря, ожидал большего