Flutter
August 19, 2022

Розробка під Android на Flutter з VS Code на сервері

Read in English

Гнучкість VS Code дозволяє займатися розробкою прямо у браузері. Прикладами є vscode.dev, що працює виключно на фронтенді, та github.dev з послугою GitHub Codespaces, що використовує віддалений сервер як потужний бекенд для аналізу коду, тоді як фронтенд є лише відображенням результатів обчислень на сервері.

Безкоштовною альтернативою GitHub Codespaces є self-hosted проєкт code-server.

Давайте розберемося як завдяки code-server та SSH налаштувати середовище для Android розробки на Flutter так, щоб потужний віддалений сервер виконував усі обчислення, а локальна малопотужна машина відображала GUI та підключала фізичний Android пристрій.

Перевірено на Ubuntu 22.04 (сервер), Fedora 36 (локальна машина) та Flutter 3.0.5.

Встановлення програмного забезпечення та SDK на сервері

1. Встановіть code-server з офіційного репозиторію

Важливо: Після встановлення code-server просить налаштувати автозапуск серверу через systemd шляхом виконання команди systemctl. Не дотримуйтесь цих вказівок, інакше VS Code не знаходитиме пристрої через ADB. Способу примусити ADB працювати сумісно з systemd поки не знайшлось.

2. Встановіть Flutter SDK та оновіть PATH

Вашій системі також можуть знадобитися додаткові залежності для запуску Flutter SDK. Рекомендовано дотримуватися офіційного посібника. Надавайте перевагу описаним там ручним способам встановлення.

Після встановлення оновіть змінну PATH у ~/.bashrc, щоб включити папку /bin з Flutter SDK, наприклад, додайте такий рядок:

export PATH="$PATH:$HOME/path/to/flutter/bin"

після чого, застосуйте зміни:

source ~/.bashrc

3. Встановлення інструментарію Android

Припустимо, на вашому сервері немає графічного середовища, тому ми встановимо інструментарій Android без Android Studio (оскільки для роботи Studio потрібен DE).

Скачування cmdline-tools

Перейдіть на сайт Android Studio та завантажте пакет "Command line tools only". Розпакуйте архів командою unzip за бажаним шляхом. Краще зробити структуру папок наступною:

~/path/to/android-sdk/cmdline-tools

Таким чином, коли sdkmanager завантажуватиме свої пакети, нові папки будуть створені всередині папки android-sdk.

Станом на серпень 2022 року для sdkmanager в інструментах командного рядка Android потрібна спеціальна ієрархія папок, яку можна досягти, помістивши вміст папки cmdline-tools в папку latest під нею за допомогою цієї команди:

mv ./cmdline-tools/ ./latest && mkdir cmdline-tools && mv ./latest/ ./cmdline-tools/latest/

Додайте інструменти до свого PATH у .bashrc і вкажіть ANDROID_SDK_ROOT, додавши нові рядки:

export ANDROID_SDK_ROOT="$HOME/path/to/android-sdk"
export PATH="$PATH:$ANDROID_SDK_ROOT/cmdline-tools/latest/bin:$ANDROID_SDK_ROOT/platform-tools"

Не забудьте запустити source ~/.bashrc

Встановіть SDK

Flutter SDK вимагає встановлення двох пакетів: build-tools і platform-tools.

sdkmanager "build-tools;33.0.0" "platform-tools"

33.0.0 — це остання версія build-tools станом на серпень 2022 року. Дізнайтеся, яка остання версія build-tools доступна, запустивши:

sdkmanager --list | grep build-tools

Погодьтесь з ліцензіями

Запустіть sdkmanager --licenses і прийміть усі ліцензії, натискаючи клавішу y

Налаштування VS Code

Після встановлення code-server ви можете отримати доступ до редактора зі свого браузера.

Також рекомендується встановити його як PWA, щоб у вас було більше місця на екрані, більше можливостей для комбінацій клавіш і можливість запускати редактор із системної панелі запуску програм.

  1. Встановіть розширення Flutter
  2. Додайте ці опції до користувацьких налаштувань VS Code:
{
    "dart.flutterRunAdditionalArgs": [
        // Dart Developer Service port (debugger)
        "--dds-port=10388",
        // Dart VM Service instance port (device)
        "--host-vmservice-port=10389"
    ],
    "dart.devToolsPort": 9100,
    "dart.devToolsLocation": "external"
}

За замовчуванням Dart вибирає випадкові порти для підключення між налагоджувачем і пристроєм. Встановлюючи ці параметри, ми робимо порти статичними, тому ми можемо їх легко переадресовувати між пристроями.

Можливо, ви захочете налаштувати dart.devToolsLocation: external через помилку code-server, яка не дозволяє завантажувати iframe Dart DevTools. Цей параметр запускає DevTools у вашому браузері за умовчанням. Причиною проблеми може бути цей issue.

Переадресація портів використовуючи SSH на локальній машині

Для налагодження програми Android за допомогою Flutter нам доведеться перенаправити 4 порти. У таблиці наведено номери портів відповідно до параметрів VS Code вище. Ви можете використовувати власні номери портів, але тоді вам доведеться відповідно змінити конфігурації.

Команди

SSH можна використовувати для перенаправлення портів.

Щоб перенаправити порт з локального хоста на віддалений хост, запустіть на локальному комп’ютері:

ssh -R XXXX:localhost:XXXX user@host

Щоб перенаправити порт із віддаленого хоста на локальний, запустіть на локальному комп’ютері:

ssh -L XXXX:localhost:XXXX user@host

Ви можете з’єднати параметри команди ssh, наприклад:

ssh -R 5037:localhost:5037 -L 10388:localhost:10388 -R 10389:localhost:10389 -L 9100:localhost:9100 user@host

Перенаправлення портів буде активним, доки ви не закриєте з’єднання SSH.

Переконайтеся, що ваш брандмауер налаштовано на переадресацію портів.

Скрипт для автоматизації

Сценарій, який автоматизує процес:

  1. Вимикає локальний ADB і перезапускає його, щоб звільнити використані порти
  2. Налаштовує переадресацію портів для вказаних портів на віддалений хост. Сценарій передбачає використання ключів для автентифікації SSH.
  3. Знищує всі запущені екземпляри code-server, node і adb. Якщо вам це не підходить, відредагуйте скрипт.
  4. Запускає ADB і запускає code-server.

Призначений для запуску на локальній машині.

#!/bin/bash

# Remote machine
CE_MACHINE="user@host"

# Local machine, no need to change
CE_LOCALHOST="localhost"

# Default port for ADB daemon is 5037
CE_ADB_PORT="5037"

# You might need to specify exact path to adb on your
# remote system since .bashrc is not sourced for
# non-interactive sessions (see https://stackoverflow.com/a/6212684)
CE_ADB_EXECUTABLE="~/dev/tools/android-sdk/platform-tools/adb"

# "Dart Developer Service port
CE_DDS_PORT="10388"

# Dart VM Service instance port
CE_HOST_VMSERVICE_PORT="10389"

# Flutter DevTools port
CE_DEVTOOLS_PORT="9100"

#### VSCode Settings ####
# "dart.flutterRunAdditionalArgs": [
# "--dds-port=10388",
# "--host-vmservice-port=10389",
# ],
# "dart.devToolsPort": 9100,
# "dart.devToolsLocation": "external",
#### VSCode Settings ####


# Reset ADB on local machine
# so it releases used ports
killall adb
adb devices

# When `adb devices` is called, ADB checks the daemon port.
# If it detects there's no response on the port, it
# launches a new daemon.
#
# After killing ADB and forwarding the ADB port to local machine,
# a newly launched ADB client will bind to the existing connection
# (which is our physical device) instead of launching a daemon on
# the remote machine.
#
# Restart code-server
# ADB doesn't detect devices if code-server is managed by systemctl
# WARNING, killing all Node processes here. Customize if needed.
#
# 1. ADB forwarding Local -> Remote
# 2. Dart Dev Server forwarding Remote -> Local
# 3. Dart on-device debugger client forwarding Local -> Remote
# 4. Flutter DevTools Remote -> Local forwarding
ssh -R $CE_ADB_PORT:$CE_LOCALHOST:$CE_ADB_PORT \
-L $CE_DDS_PORT:$CE_LOCALHOST:$CE_DDS_PORT \
-R $CE_HOST_VMSERVICE_PORT:$CE_LOCALHOST:$CE_HOST_VMSERVICE_PORT \
-L $CE_DEVTOOLS_PORT:$CE_LOCALHOST:$CE_DEVTOOLS_PORT \
$CE_MACHINE "killall code-server; killall node; killall adb; $CE_ADB_EXECUTABLE devices; code-server"