17 KiB
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:
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:
puro create bachelor_elinux 3.19.2
Nachdem die Umgebung erstellt wurde, kann diese mit dem Befehl im Pfad des Projekts genutzt werden:
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.
Einrichtung des Raspberry Pis als Entwicklungsplattform
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:
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.
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:
# 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:
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:
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:
{
"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.