## Entwicklungsumgebung

In diesem Kapitel wird die Entwicklungsumgebung
für die Implementierung der Fallstudie beschrieben.
Hierbei wird erklärt wie das Flutter Projekt
aufgesetzt wurde und wie man es zur Entwicklung
mit eingebetteten Linux Systemen wie dem Raspberry Pi
konfiguriert.

In der Entwicklungsumgebung wird davon ausgegangen, dass
entweder ein Linux oder macOS System genutzt wird, weil
Windows zu diesem Zeitpunkt nicht unterstützt wird (genauer
erläutert in Kapitel \ref{raspberrySetup}). In
Windows sollten die Schritte mit WSL (Windows Subsystem
for Linux) nachvollzogen werden. WSL erlaubt es eine
vollwertige Linux Distribution in Windows zu nutzen [@InstallWSL2023].
Die Nutzung von WSL wurde jedoch nicht getestet, das Projekt
wurde nur mit Linux und macOS durchgeführt. Es ist also
möglich, dass es zu Probleme bei der Nutzung von Windows kommen kann.

### Visual Studio Code

Für die Implementierung wurde die
plattformübergreifende Open-Source-Entwicklungsumgebung
Visual Studio Code (VS Code) von Microsoft verwendet.
VS Code ist eine sehr beliebte Entwicklungsumgebung
für die Entwicklung von Webanwendungen, mobilen
Anwendungen und Desktopanwendungen. Die Entwicklungsumgebung
bietet eine Vielzahl von Erweiterungen, die die
Entwicklung von Anwendungen in verschiedenen
Programmiersprachen und Frameworks unterstützen.

#### Genutzte Erweiterungen

In dem Reiter "Erweiterungen" (Strg + Shift + X in Windows/Linux, Command + Shift + X in macOS)
in VS Code wurden die folgenden Erweiterungen installiert:

- dart-code.dart-code
- dart-code.flutter
- circlecodesolution.css-flutter-color
- djbkwon.flutter-dependency-docs
- pkief.material-icon-theme
- alejandro-fa.vscode-theme-dartpad

Dazu gehören die offiziellen Erweiterungen für Flutter und Dart
von Google (dart-code.dart-code und dart-code.flutter), ein Plugin
für die Anzeige von Farben in Editor bei Dart Code (circlecodesolution.css-flutter-color),
ein Plugin für die Anzeige der Links zu den Dokumentationen der
Abhängigkeiten in der pubspec.yaml Datei (djbkwon.flutter-dependency-docs)
und zwei Plugins für die Anpassung des Themes von VS Code (pkief.material-icon-theme, alejandro-fa.vscode-theme-dartpad).
Bei der Icon Theme "Material Icon Theme" empfiehlt es sich den Befehl "Material Icons: Change Folder Theme" auszuführen und "None" auszuwählen,
damit die Ordnerstruktur des Projektes besser dargestellt wird. Das Theme "DartPad Candy" ist zusätzlich auch
zu empfehlen, da es die Farben des Editors zu denen vom DartPad anpasst. DartPad
ist ein Online-Editor für Flutter und Dart, welcher von Google entwickelt wurde [@DartPad].
Das Farbdesign ist dadurch angenehmer als das Standarddesign von VS Code
für die Entwicklung von Flutter Anwendungen, da es speziell für die Dart
Programmiersprache angepasst ist.

Mit Windows die Erweiterung "ms-vscode-remote.remote-wsl" installiert werden,
mit der das WSL System in VS Code integriert wird. Danach sollte man
zu diesem WSL System wechseln.

### Flutter Versionsverwaltung

Das Versionsmanagement von Flutter ist standardmäßig
sehr einfach gehalten. Es gibt nur eine globale
Installation von Flutter, die manuell auf dem System
installiert wird. Diese globale Installation
arbeitet mit Git und nutzt verschiedene Branches
für die verschiedenen Versionen von Flutter,
diese Branches nennt Google Channels. Die
Channels sind _stable_, _beta_ und _master_.
Die _stable_ Version ist immer die aktuellste
stabile Version von Flutter, diese wird für die
Produktion und für die meisten Entwickler empfohlen.
Die _beta_ Version ist die neueste stabile Version
von Flutter, welche neue Features beinhalten kann und
nicht für die Produktion empfohlen wird. Diese Version
wird später zur nächsten _stable_ Version höhergestuft
und wird von Google jedoch auch bereits extensiv getestet
und sollte sehr stabil sein. Die _master_ Version ist die neueste
Entwicklungsversion von Flutter, diese Version ist
nicht stabil und wird nicht für die Produktion
empfohlen. Diese Version beinhaltet alle neuesten
Commits welche von Entwicklern in das Flutter
Repository gepusht wurden [@googleinc.UpgradingFlutter].

Hierbei gibt es jedoch einige Probleme, die
durch die globale Installation von Flutter
entstehen. Die globale Installation von Flutter
ist nicht für die Arbeit mit verschiedenen
Projekten und verschiedenen Versionen von Flutter
ausgelegt. Es gibt keine Möglichkeit, verschiedene
Versionen von Flutter zu installieren und zu
verwalten. Außerdem gibt es keine einfache Möglichkeit,
eine bestimmte Version von Flutter zu installieren,
es wird immer die neueste _stable_, _beta_ oder
_master_ Version installiert. So wurde in der
Entwicklung der Anwendung von der Fallstudie Flutter Version 3.19.2
verwendet, welche jedoch zu einem späteren Zeitpunkt
nicht mehr aktuell ist.

Zur Lösung dieser Probleme wurde in dem Projekt
Puro verwendet. Puro ist ein in Dart geschriebenes
CLI (Command Line Interface, dt. Kommandozeile) Tool, welches es ermöglicht,
verschiedene Versionen von Flutter zu installieren
und zu verwalten. Dazu bietet Puro eine Integration
mit den Entwicklungsumgebungen VS Code und IntelliJ.
Puro ist Open-Source und auf GitHub verfügbar [@PingbirdPuro2024].
Im folgenden wird erklärt wie Puro genutzt wird um Flutter
zu installieren und wie es im Projekt konfiguriert wird.

#### Puro Installation

Unter MacOS und Linux kann Puro mit dem folgenden
CLI-Befehl installiert werden:

```bash
curl -o- https://puro.dev/install.sh | PURO_VERSION="1.4.5" bash
```

Puro unterstützt hierbei unter Linux und Windows zur Zeit
der Arbeit nur die AMD64 Architektur (Intel und AMD Prozessoren).
Unter macOS wird neben AMD64 auch die ARM64 Architektur (Apple Silicon Prozessoren)
unterstützt.

#### Installation von Flutter mit Puro

Puro arbeitet mit Umgebungen (Environments) um die verschiedenen
Versionen von Flutter zu verwalten.
In der Anwendung der Fallstudie wurde die Umgebung
auf "_bachelor_elinux_" gesetzt, diese Umgebung
muss folgendermaßen erstellt werden:

```{.bash .number-lines caption="Erstellung der Puro Umgebung" captionpos=t label=CreateBachelor}
puro create bachelor_elinux 3.19.2
```

Nachdem die Umgebung erstellt wurde, kann diese
mit dem Befehl im Pfad des Projekts genutzt werden:

```{.bash .number-lines caption="Nutzung der Puro Umgebung im Pfad" captionpos=t label=UseBachelor}
puro use bachelor_elinux
```

Puro erstellt dann eine _.puro.json_ Datei
und passende Einstellungen in _.vscode/settings.json_
in dem Pfad des Projektes. Dadurch nutzt VS Code
automatisch die richtige Version von Flutter
wenn das Flutter Projekt gestartet wird.

<!-- MacOS und Linux

```bash
curl -o- https://puro.dev/install.sh | PURO_VERSION="1.4.4" bash
```

Windows

```powershell
Invoke-WebRequest -Uri "https://puro.dev/builds/1.4.4/windows-x64/puro.exe" -OutFile "$env:temp\puro.exe"; &"$env:temp\puro.exe" install-puro --promote
```

Puro Optimierungen:

- parallel git clone and engine download
- global cache for git history
- global cache for engine versions

With other approaches, each Flutter repository is in its own folder, requiring you to download and store the git history, engine, and framework of each version:

Puro implements a technology similar to GitLab's object deduplication to avoid downloading the same git objects over and over again. It also uses symlinks to share the same engine version between multiple installations:

```bash
puro use -g stable
```

```bash
puro create bachelor_elinux 3.19.0
```

```bash
puro use bachelor_elinux
```

`.puro.json`:

```json
{
  "env": "bachelor_elinux"
}
```

`.vscode/settings.json`

```json
{
  "dart.flutterSdkPath": "/Users/pi/.puro/envs/bachelor_elinux/flutter",
  "dart.sdkPath": "/Users/pi/.puro/envs/bachelor_elinux/flutter/bin/cache/dart-sdk"
}
```

```bash
puro flutter --version
```

```bash
Flutter 3.19.0 • channel stable • https://github.com/flutter/flutter.git
Framework • revision bae5e49bc2 (6 days ago) • 2024-02-13 17:46:18 -0800
Engine • revision 04817c99c9
Tools • Dart 3.3.0 • DevTools 2.31.1
```

## Setup von Raspberry Pi -->

### Einrichtung des Raspberry Pis als Entwicklungsplattform {#raspberrySetup}

In diesem Kapitel wird die Einrichtung des Raspberry Pi
als Entwicklungsplattform für die Implementierung der Flutter Anwendung
beschrieben.

#### Raspberry Pi Imager

Mit dem Programm _Raspberry Pi Imager_ kann das offizielle
und auf Debian basierte Betriebssystem _Raspberry Pi OS_
auf eine SD-Karte geschrieben werden [@raspberrypiltd.RaspberryPiOS]. In dem Programm
kann man dazu unter "Advanced Options" den SSH Zugriff
aktivieren und den öffentlichen SSH Schlüssel hinzufügen.
Die Informationen der Benutzeroberfläche machen es hier nicht
ganz klar, aber damit ist gemeint, dass der Schlüssel des
Gerätes von dem aus der Imager genutzt wird, in dem
Raspberry Pi OS vorkonfiguriert wird. Es wird also erwartet,
dass das Gerät, von dem aus der Imager genutzt wird, auch
zum Zugriff auf den Pi per SSH genutzt wird. Diese Option
sorgt dafür, dass man sich von dem PC, auf dem der Imager genutzt
wurde, ohne Passwort-Eingabe per SSH mit dem Pi verbinden kann.

\begin{figure}[H]
\caption{Ausgewählte Optionen im Raspberry Pi Imager}
\label{newsList}
\centering
{\shadowimage[width=7cm]{./assets/raspberry/imagerOptions.png}}
\end{figure}

Im Imager muss zusätzlich auch die Version vom Raspberry Pi OS
mit Desktop ausgewählt werden. Es wird empfohlen diese Version
zu nutzen, weil hier sicher ist, dass alle Grafikkarten und Eingabegeräte Treiber
und Bibliotheken wie Schriftarten installiert sind. Diese werden
für die Flutter Anwendung benötigt.

#### Deaktivierung des Desktops

Der Desktop von Raspberry Pi OS ist nicht notwendig und
muss in dem "raspi-config" Kommandozeilen-Programm deaktiviert werden:

```{.bash .number-lines caption="Starten von raspi-config" captionpos=t label=raspiConfig}
sudo raspi-config
```

In Raspi-Config muss dann unter "System Options" und "Boot / Auto Login"
die Option "Console" ausgewählt werden und der Raspberry muss neugestartet werden.
Dies ist notwendig da Flutter-Pi ohne Desktop-Server genutzt werden muss.

<!-- #### Tailscale

```bash
curl -fsSL https://tailscale.com/install.sh | sh
``` -->

#### Installation Flutter-Pi

Danach kann Flutter-Pi nach der offiziellen Anleitung
aus der README Datei des Projekts auf GitHub installiert
werden [@winklerArderaFlutterpi2024]. Im Folgenden werden die
notwendigen Befehle dazu gelistet:

```{.bash .number-lines caption="Installation von Flutter-Pi" captionpos=t label=FlutterPiInstallation}
# Installation aller Abhängigkeiten
sudo apt install cmake libgl1-mesa-dev libgles2-mesa-dev libegl1-mesa-dev libdrm-dev libgbm-dev ttf-mscorefonts-installer fontconfig libsystemd-dev libinput-dev libudev-dev  libxkbcommon-dev
sudo apt install libgstreamer1.0-dev libgstreamer-plugins-base1.0-dev libgstreamer-plugins-bad1.0-dev gstreamer1.0-plugins-base gstreamer1.0-plugins-good gstreamer1.0-plugins-ugly gstreamer1.0-plugins-bad gstreamer1.0-libav gstreamer1.0-alsa
# Aktualisierung der Schriftarten
sudo fc-cache
# Installation von Flutter-Pi
git clone https://github.com/ardera/flutter-pi
cd flutter-pi
mkdir build && cd build
cmake ..
make -j`nproc`
sudo make install
```

Flutter-Pi kommt mit einem eigenen Build-Tool, welches
genutzt werden muss um die Flutter Anwendungen für Flutter-Pi
zu kompilieren. Dieses Tool kann mit dem folgenden Befehl
installiert werden:

```{.bash .number-lines caption="Installation von flutterpi_tool" captionpos=t label=FlutterPiTool}
puro flutter pub global activate flutterpi_tool
```

Das Build-Tool von Flutter-Pi funktioniert momentan nur auf Linux und
macOS Systemen.

#### Hinzufügen des Raspberry Pis als Custom Device

Zuletzt muss der Raspberry Pi als "Custom Device" (dt. Angepasste Geräte) zu
der Flutter Konfiguration auf dem PC hinzugefügt werden,
auf dem vorher der Imager genutzt wurde und VS Code und Puro
installiert wurden. In der GitHub Wiki von Flutter wird
erklärt wie man "Custom Embedder" als "Custom Devices" zur
lokalen Flutter Installation hinzufügen kann [@UsingCustomEmbeddersa].
Die Informationen sind jedoch sehr spärlich und vieles musste
durch Ausprobieren herausgefunden werden.

Zuerst müssen die Custom Devices aktiviert werden:

```{.shell .number-lines caption="Installation von Flutter-Pi" captionpos=t label=customDevicesEnable}
puro flutter config --enable-custom-devices
```

Durch die Ausführung des Befehls wird die Datei _~/.config/flutter/custom_devices.json_ erstellt
und für die lokale Flutter Installation wurde aktiviert, dass Custom Devices aus dieser
Datei ausgelesen werden können.

In der Datei _custom_devices.json_ wird dann der Raspberry Pi
hinzugefügt werden. Da die Dokumentationen dazu sehr spärlich
sind, folgt hier die komplette Konfiguration für den Raspberry Pi 4
welche auch in dem Projekt verwendet wurde:

```{.json .number-lines caption="Beispiel Konfiguration von custom_devices.json" captionpos=t label=customDevicesJson}
{
  "custom-devices": [
    {
      "id": "rpi",
      "label": "Raspberry Pi 4",
      "sdkNameAndVersion": "rpi4",
      "platform": null,
      "enabled": true,
      "ping": ["ping", "-c", "1", "raspberrypi"],
      "pingSuccessRegex": null,
      "postBuild": ["flutterpi_tool", "build", "--arch=arm64", "--cpu=pi4"],
      "install": [
        "scp",
        "-r",
        "-o",
        "BatchMode=no",
        "${localPath}",
        "pi@raspberrypi:/tmp/${appName}"
      ],
      "uninstall": [
        "ssh",
        "-o",
        "BatchMode=no",
        "pi@raspberrypi",
        "rm -rf \"/tmp/${appName}\""
      ],
      "runDebug": [
        "ssh",
        "-o",
        "BatchMode=no",
        "pi@raspberrypi",
        "flutter-pi /tmp/${appName}"
      ],
      "stopApp": [
        "ssh",
        "-o",
        "BatchMode=no",
        "pi@raspberrypi",
        "pkill",
        "flutter-pi"
      ],
      "forwardPort": [
        "ssh",
        "-o",
        "BatchMode=no",
        "-o",
        "ExitOnForwardFailure=yes",
        "-L",
        "127.0.0.1:${hostPort}:127.0.0.1:${devicePort}",
        "pi@raspberrypi",
        "echo 'Port forwarding success'; read"
      ],
      "forwardPortSuccessRegex": "Port forwarding success",
    }
  ]
}
```

Im Quellcode von Flutter konnte zu der _custom-devices.json_ Datei die
Schema-Datei _custom-devices.schema.json_ gefunden werden, welche
als Referenz und Hilfe für die Konfiguration genutzt wurde.

In der Beispielkonfiguration von Auflistung \ref{customDevicesJson} wird
der Raspberry Pi 4 als Custom Device mit dem Label "Raspberry Pi 4"
und der ID "rpi" hinzugefügt. Der "ping" Befehl wird genutzt um zu
überprüfen ob das Gerät erreichbar ist und wenn es ist, wird es
bei der Ausführung von Flutter mit dem definierten Label
und der ID in der Geräteliste angezeigt.

Im "postBuild" Befehl wird das
Flutter-Pi Build-Tool mit den Parametern "--arch=arm64" und "--cpu=pi4"
genutzt um die Anwendung für den Pi 4 und der ARM64 Architektur zu
kompilieren. Aus der Dokumentation des Flutter-Pi Build-Tools kann entnommen werden,
dass es beim "cpu" Parameter nur die Optionen "pi3" und "pi4" gibt, welche
spezielle Optimierungen für den Raspberry Pi 3 und 4 beinhalten. Für alle anderen
Geräte kann der Parameter weg gelassen werden und nur der passende "arch" Parameter
zur Prozessorarchitektur ist wichtig mit den Optionen "arm", "arm64" und "x64".
Es werden alle Geräte mit diesen Prozessortypen unterstützt [@winklerArderaFlutterpi_tool2024].

Mit dem "install" Befehl wird die Anwendung
mit dem _scp_ Kommandozeilen-Befehl (OpenSSH Secure Copy)
vom lokalen PC auf den Raspberry Pi kopiert. Dank des SSH Schlüssels,
welcher im Imager hinzugefügt wurde, ist keine Passwort-Eingabe
notwendig wie auch bei allen anderen folgenden SSH Befehlen aus
der Konfiguration. Als Ordner wird ein temporärer Ordner auf dem
Pi genutzt, in Linux wird dazu das _/tmp_ Verzeichnis genutzt.
Alle Dateien darin werden nach einem Neustart des Geräts gelöscht.

Der "uninstall" Befehl löscht dann die Anwendung wieder manuell vom Raspberry Pi
und der "runDebug" Befehl startet die Anwendung auf dem Pi mit dem _flutter-pi_
Befehl. Der "stopApp" Befehl stoppt die Anwendung auf dem Pi manuell
mit dem _pkill_ Befehl.
Im "forwardPort" Befehl wird ein Port auf dem Pi auf einen Port auf dem
lokalen PC weitergeleitet, dies ist notwendig um die Anwendung auf dem
Pi zu debuggen.

Nach der Konfiguration kann der Raspberry Pi beim Ausführen der
Flutter Anwendung ausgewählt werden und die Anwendung kann auf dem
Raspberry Pi gestartet werden, während der Code auf dem lokalen PC
in VS Code geschrieben und debuggt werden kann. Dabei funktioniert
auch das Hot-Reload Feature von Flutter.

Im Test funktioniert diese Konfiguration gut, es gibt aber ein paar Probleme.
Beim Beenden der Anwendung wird der _stopApp_ Befehl nicht ausgeführt, der
Befehl in der Konfiguration kann aber manuell ausgeführt werden und funktioniert
dann. Zusätzlich funktioniert der Hot-Reload nicht beim ersten Mal und es
wird der Fehler aus Abbildung angezeigt. Es kann dann ein Hot-Restart
durchgeführt werden und danach funktioniert auch das Hot-Reload Feature
wie erwartet. Ein paar Mal kam es aber auch vor, dass die App dabei abstürzte.
Es funktioniert also gut, ist aber noch instabil.

\begin{figure}[H]
\caption{Die Fehlernachricht beim ersten Hot-Reload}
\label{newsList}
\centering
{\includegraphics[width=10cm]{./assets/raspberry/hotReloadError.png}}
\end{figure}

Der Fehler tritt wahrscheinlich auf, weil die Anwendung nicht den Einstiegspunkt
in der "_MaterialApp_" richtig neuladen kann. Es ist aber unklar wieso
es nur beim ersten Mal passiert und die Fehlernachricht hilft in diesem
Fall nicht weiter.

# Implementierung der Features {#features}
