Projekt

RadioAtlas - Die Welt Sender für Sender entdecken

Wie ich eine iPraktikum-prämierte iOS-App gebaut habe, die globale Radiokultur mit SwiftUI, SwiftData und der Radio Browser API erkundbar macht.

12 Min. Lesezeit15.11.2025Justin Lanfermann
RadioAtlas hero graphic showcasing a glowing globe with highlighted radio station clusters

RadioAtlas ist meine Liebeserklärung an Radiokultur: ein kartenbasierter Radio Explorer, der zehntausende Sender in Pins verwandelt, die du antippen, durchstöbern und wie musikalische Postkarten speichern kannst. Angefangen hat es als TUM iPraktikum Introcourse-Projekt mit nur sieben Tagen Zeit. Ziemlich schnell wurde daraus eine echte Obsession mit einer Frage: Wie weit kann man moderne iOS-Frameworks treiben, damit sich Radio für Leute, die mit Autoplay-Queues aufgewachsen sind, wieder abenteuerlich anfühlt?

Radiokultur durch eine interaktive Weltkarte bewahren - ein iOS-App-Post-mortem.

TL;DR

Mit RadioAtlas hörst du dich in Orte hinein, nicht in Playlists. Unter der Haube kombiniert die App die Community-getriebene Radio Browser API, SwiftUI, SwiftData, ein lazy-loaded MapKit-Interface und einen eigenen Playback-Stack, der in Apples Now Playing-System integriert ist. Das Ergebnis ist ein Globus, auf dem jeder Pin eine Geschichte ist: Tippe auf München, Botswana oder ein zufälliges Dorf im ländlichen Australien und du hörst sofort lokales Radio, inklusive Background Audio, Apple Watch und CarPlay.

Radio ist nicht tot, aber es ist fragil. Sender verschwinden leise, wenn Werbegeld woanders hinwandert, und algorithmische Playlists füllen die Lücke mit perfekt optimierter, perfekt vergessbarer Hintergrundmusik. Mit jedem Sender, der verschwindet, verlierst du mehr als eine URL: Akzente, Lokalnachrichten, schräge Morgenshows und diesen einen seltsamen Jingle, den in einer Stadt jeder auswendig kennt. RadioAtlas entstand aus genau diesem Gefühl. Statt noch einem „Genre + Stimmung“-Picker wollte ich eine App bauen, die sagt: Such dir einen Ort auf der Karte aus und wir beamen dich in das, was die Menschen dort gerade hören.

Wie bringt man eine Generation, die mit sofortigem, algorithmischem Streaming aufgewachsen ist, wieder dazu, traditionelles Radio zu entdecken?

Meine Antwort war: Entdeckung in den Mittelpunkt stellen. RadioAtlas öffnet nicht mit einer Liste, sondern mit einem Globus. Du zoomst, ziehst und bewegst dich über Kontinente, während Sendercluster beim Hineinzoomen zu einzelnen Pins auseinanderfallen. Es fühlt sich weniger an wie das Scrollen durch eine Playlist und mehr wie das Drehen eines echten Globus, irgendwo mit dem Finger stoppen und fragen: „Wie klingt dieser Ort genau jetzt?“

Dieser Fokus auf Kultur und Spieltrieb hat sich ausgezahlt. Was als Studierendenprojekt begann, gewann am Ende den 1. Platz im Winter 25/26 iPraktikum Introcourse-Wettbewerb. Der Pokal ist nett, aber der eigentliche Gewinn war zu sehen, wie ein ganzer Raum realisierte, dass man mit zwei Taps von einem kleinen bayerischen Dorfsender zu einem Jazz-Stream in New York springen kann.

Motivation und Vision

Ich habe RadioAtlas gebaut, um den Kontext von Radio lebendig zu halten. Wenn du in der App einen Sender einschaltest, startest du nicht einfach „einen Stream“, du springst in eine bestimmte Sprache, Stadt und einen bestimmten Moment. Dieses Framing hat still fast jede Produktentscheidung beeinflusst. Der Homescreen ist eine Karte, keine Tabellenansicht. Senderkarten zeigen zuerst Ort und Identität, bevor sie über Bitrate oder Tags sprechen. Onboarding fragt dich nicht nach Genres, sondern bietet dir Orte an: Spring direkt dorthin, wo du aufgewachsen bist, wo du jetzt lebst oder wo du noch nie warst.

Weil die Zielgruppe extrem polierte Streaming-Apps gewohnt ist, musste RadioAtlas verspielt statt nostalgisch wirken. Über Cluster zu schwenken, in kleine Städte hineinzuzoomen und deine Senderhistorie zurückzuspulen fühlt sich eher wie ein leichtes Spiel an als wie ein Werkzeug. In jeder Interaktion steckt ein bisschen Neugier: Was passiert, wenn ich auf diese winzige Insel zoome? Was passiert, wenn ich in der Senderhistorie immer weiter „weiter“ drücke, bis mir die App etwas völlig Unerwartetes vorspielt?

Der kartenbasierte Homescreen hält die Entdeckung greifbar, Senderkarten starten mit Ort und Identität statt technischen Details, und kleine Neugier-Schleifen wie Verlauf, Zufallssprünge und Zooms bringen dich dazu, weiterzuwandern, statt beim ersten Stream stehenzubleiben.

Was RadioAtlas konkret macht

Unter der romantischen „Hör dir die Welt an“-Idee macht RadioAtlas sehr konkrete Dinge. Die App zieht einen riesigen Katalog von Internetradiosendern aus der Community-getriebenen Radio Browser API und verwandelt ihn in eine weltweite Karte, die man auf einem iPhone wirklich bedienen kann. Aus dieser gemeinsamen Datenbank kennt die App große Sender in Hauptstädten, winzige ehrenamtliche Stationen aus Community-Zentren und alles dazwischen. Sobald diese Sender lokal gespeichert sind, kannst du browsen, suchen, Favoriten speichern und zwischen zuletzt gehörten Sendern springen wie zwischen Browser-Tabs.

Die Discovery Experience ist kartenbasiert. Du startest mit einem Globus voller Sendercluster. Zoom nach Europa, dann Deutschland, dann München, und die Cluster lösen sich in einzelne Pins auf. Tippst du einen Sender an, fährt ein Now Playing-Sheet mit Name, Ort und, falls der Sender sie liefert, aktuellen Track-Metadaten hoch. Du kannst Sender favorisieren, teilen oder das Sheet schließen und weiter erkunden. Wenn du gerade keine Kartenstimmung hast, kannst du in einer eigenen Suche nach Name, Land, Sprache oder Tags suchen. Dabei kombiniert die App lokalen Cache mit Live-API-Abfragen, damit du nicht auf einen vollständigen globalen Sync warten musst, um etwas Bestimmtes zu finden.

Alles, was du berührst, bleibt erhalten. Jeder Sender, den du gespielt oder als Favorit gespeichert hast, landet in SwiftData. Dadurch verhält sich dein Verlauf wie ein Browser: Du kannst durch die Orte, die du besucht hast, zurück- und vorwärtsgehen. Wenn du am Ende dieses Stacks ankommst und immer noch neugierig bist, wirft RadioAtlas dich auf einen zufälligen Sender aus der Datenbank, ein „I'm feeling lucky“-Button im Radio-Gewand.

Cluster lösen sich beim Zoomen in einzelne Pins auf, die Suche mischt gecachte Daten mit Live-Lookups, wenn du Präzision brauchst, und der Besuchsverlauf funktioniert wie ein Browser, sodass du zurückspringen, vorwärtsgehen oder einen zufälligen Sender ausprobieren kannst.

Übersicht der RadioAtlas-Features in einem Grid mit Karte, Suche, Favoriten und Verlauf
RadioAtlas auf einen Blick: die Hauptfunktionen in einer klaren Übersicht, Kartenentdeckung, Suche, Favoritenverwaltung und Hörverlauf.

Unter der Haube: Architektur und Datenfluss

Damit sich das auf einem Handy mühelos anfühlt, brauchte es eine ziemlich disziplinierte Architektur, auch wenn die UI bewusst verspielt ist. Das Rückgrat ist die Radio Browser API, die Sender-Metadaten, Stream-URLs und Geo-Koordinaten über HTTP-Endpunkte bereitstellt. Statt beim Start die gesamte Datenbank zu laden und auf das Beste zu hoffen, schrieb ich einen kleinen Swift-Client, der die verschiedenen Mirrors kennt, sich von Fehlern erholen kann und Antworten in lokale RadioStation-Modelle übersetzt.

Beim ersten Start führt die App einen Eager Sync der ungefähr zehntausend beliebtesten Sender aus. Dadurch hat die Karte sofort etwas Sinnvolles anzuzeigen, auch bei schwacher Verbindung, und der lokale SwiftData-Store bekommt eine solide Basis. Ab dann ist alles inkrementell. Die Karte sagt der Datenschicht, welche Region sichtbar ist, und das Repository antwortet mit Sendern innerhalb dieser Bounding Box. Wenn du verschiebst oder zoomst, löst ein debounced Callback eine weitere Anfrage aus, und SwiftUI rendert dank Diffing nur die Änderungen neu.

Damit Städte nicht zu unlesbaren Pin-Meeren werden, habe ich eine Clustering-Schicht integriert. Viele Sender auf derselben Zoomstufe fallen dadurch zu einem einzigen Icon mit Zähler zusammen. Beim Hineinzoomen teilen sich die Cluster natürlich auf. Diese Kombination aus viewport-aware Loading und Clustering bedeutet, dass die App selten mehr als ein paar hundert Annotationen gleichzeitig verwalten muss, obwohl sie Zugriff auf zehntausende Sender hat.

Der Rest der Architektur folgt einem sauberen, geschichteten Ansatz. SwiftUI-Views sind so simpel wie möglich: Sie rendern Listen von Sendern und einfachen View State, nicht mehr. Application State lebt in einigen @Observable-basierten Managern wie RadioPlayerManager und StationHistoryManager, während das von SwiftData gestützte StationRepository für API-Kommunikation, Schreiben auf die Disk und den täglichen Refresh zuständig ist. Jedes Teil hat eine kleine, klar definierte Aufgabe, was Debugging und Iteration deutlich weniger dramatisch gemacht hat.

Die Radio Browser API füttert einen robusten Client mit Mirror-Handling und Retries, StationRepository + SwiftData übernehmen Persistenz und Refresh-Rhythmus, und einige @Observable-Manager treiben bewusst simple SwiftUI-Views an.

Bild wird geladen...
RadioAtlas im Einsatz auf einem iPhone unterwegs
RadioAtlas in freier Wildbahn: globale Radiosender unterwegs erkunden.

Playback und das Apple-Ökosystem

Eine Radio-App wird nicht daran gemessen, wie schön ihre Karte ist, sondern daran, was passiert, wenn du den Bildschirm ausschaltest. RadioAtlas sollte sich wie jede ernstzunehmende Audio-App verhalten: Wiedergabe im Hintergrund, ordentliche Lock-Screen-Controls, Apple Watch-Integration und sinnvolles Verhalten im Auto. Dafür habe ich den Open-Source-Player FRadioPlayer in einen eigenen Manager verpackt und den Rest der Experience um Apples MediaPlayer-Framework herum gebaut.

Sobald du einen Sender startest, aktualisiert die App das systemweite MPNowPlayingInfoCenter mit Sendername, Ort und Artwork. Wenn der Stream Metadaten liefert, erscheinen dort auch aktueller Track und Artist. Genau dieses Payload speist das Lock-Screen-Widget, die Control-Center-Kachel, Dynamic Island und den Now Playing-Screen der Apple Watch. Du kannst also eine australische Frühstücksshow vom Handgelenk pausieren, während du an einem Münchner U-Bahnsteig stehst, und es fühlt sich komplett nativ an.

Remote Commands hängen am Senderverlauf. Play und Pause sind offensichtlich, aber Next und Previous werden zu „vorwärts“ und „zurück“ in deinen besuchten Sendern. Dieses Mapping funktioniert über AirPods-Controls, Lenkradtasten in CarPlay und die kleinen Buttons im Control Center. Es fühlt sich überraschend natürlich an, so durch Sender zu blättern, als würdest du an einem alten Radio drehen, nur dass die Kanäle über den ganzen Planeten verteilt sind.

Now Playing-Metadaten versorgen Lock Screen, Control Center, Dynamic Island und Apple Watch, und dieselben verlaufsbewussten Controls funktionieren über AirPods, Lenkräder und kleine Control-Center-Buttons hinweg. Timeouts, freundliche Fehlermeldungen und OSLog-Traces verhindern, dass kaputte Streams die App blockieren.

Live-Radio-Streaming ist von Natur aus chaotisch, also habe ich einen Timeout und explizite Fehlerzustände eingebaut. Wenn ein Sender innerhalb von ungefähr fünfzehn Sekunden nicht buffert, gibt die App auf, stoppt die Wiedergabe und zeigt eine freundliche Fehlermeldung, statt endlos zu drehen. Die schmutzigen Details landen in OSLog, damit ich sie später prüfen kann. Nutzer sehen nur eine klare „dieser Sender scheint offline zu sein“-Nachricht, statt raten zu müssen.

Bild wird geladen...
RadioAtlas Now Playing-Screen mit Senderdetails und Wiedergabesteuerung
Die Now Playing-Experience: Sender-Metadaten, Artwork und Controls, die dich auf Lock Screen, Apple Watch und CarPlay begleiten.

Ein kurzer Rant über TabViewBottomAccessoryPlacement

Lass mich von einem der frustrierendsten Nachmittage dieses Projekts erzählen. iOS 26 führte diese schöne neue API namens TabViewBottomAccessoryPlacement und TabBarMinimizeBehavior ein: ein Tab-Bar-Accessory, das über deiner Tab Bar sitzt und beim Scrollen elegant in sie minimieren kann. Perfekt für einen persistenten Mini-Player, oder? Nur besteht die Dokumentation aus ungefähr drei Sätzen und verrät dir praktisch nichts darüber, wie das wirklich funktioniert.

Ich verbrachte Stunden damit, das Minimize-Verhalten auszulösen. Das Accessory saß einfach da und weigerte sich stur, einzuklappen, egal wie viel ich scrollte. Wie sich herausstellte, und das steht exakt nirgendwo, funktioniert das Verhalten nur, wenn deine View eine bestimmte Mindesthöhe hat. Zu kurz? Dann minimiert es nicht. Der Schwellenwert? Viel Spaß beim Herausfinden. Apples Implementierung ist in bestimmten Edge Cases außerdem herrlich buggy, mit einem Accessory, das gelegentlich halb hängen bleibt oder zum falschen Zeitpunkt animiert.

Trotzdem: Wenn man es einmal bezwungen hat, ist das Tab-Bar-Accessory tatsächlich wirklich schön. Es gibt dir eine persistente Kontrollfläche, ohne Bildschirmfläche zu verschwenden, und wenn es funktioniert, fühlt sich die Minimize-Animation poliert und nativ an. Ich wünschte nur, Apple hätte mehr als eine Fußnote dazu geschrieben, wie man es benutzt. Vielleicht bekommen wir bis iOS 36 ordentliche Dokumentation. Oder zumindest eine WWDC-Session, die die Höhenanforderungen erwähnt.

Höhe zählt. Das Accessory minimiert nur, wenn deine View einen versteckten Schwellenwert überschreitet, also plane vertikalen Spielraum ein. Rechne mit Eigenheiten. Halb eingeklappte Zustände und seltsame Timings passieren, also baue leichte Leitplanken. Trotzdem lohnt es sich. Richtig abgestimmt fühlt sich der Mini-Player nativ an, ohne Platz zu stehlen.

Performance, Caching und Offline-Verhalten

Die größte Performance-Herausforderung war leicht zu beschreiben und leicht zu unterschätzen: Ein globales Verzeichnis von Radiosendern soll sich auf einem Handy leichtgewichtig anfühlen. Die Antwort steckt in ein paar Prinzipien, die fast jeden Teil der App prägen. Daten werden immer just-in-time für die aktuelle Ansicht geladen. Der initiale Sync lädt nur eine nützliche, beliebte Teilmenge der Sender. Alles, was den Main Thread blockieren könnte, wandert in Async-Arbeit mit unaufdringlichen Loading States in der UI.

Die Datenschicht holt nur, was der aktuelle Viewport braucht, startet mit einer schlanken beliebten Teilmenge, damit die Karte sofort Signal hat, und schiebt schwerere Arbeit vom Main Thread weg, während die UI ruhig bleibt.

SwiftData hilft, den Speicherverbrauch vernünftig zu halten, weil ich Sender in einer echten On-Device-Datenbank speichern kann, statt riesige In-Memory-Arrays zu jonglieren. Die App muss normalerweise nicht mehr als ein paar tausend Senderobjekte gleichzeitig lebendig halten. Zusammen mit SwiftUIs Diffing und MapKits Clustering reicht das, damit Scrollen und Zoomen auch auf älteren Geräten flüssig bleibt.

Damit alles frisch bleibt, läuft ungefähr einmal täglich ein Background Task und fragt die Radio Browser API, was neu ist. Neue Sender werden zusammengeführt, bestehende aktualisiert und kaputte Einträge können mit der Zeit aussortiert werden. Nutzer sehen nie einen manuellen „Verzeichnis aktualisieren“-Button, die Karte entwickelt sich einfach im Hintergrund weiter. Favoriten und Hörverlauf leben ebenfalls vollständig in SwiftData. Dadurch kannst du deine gespeicherten Sender und alten Picks auch offline durchsuchen und die Wiedergabe starten, sobald deine Verbindung zurückkommt.

Showtime: RadioAtlas präsentieren

Irgendwann mussten all die Architekturdiagramme und Swift-Dateien ihrem Endgegner gegenübertreten: der Live-Präsentation. Vor einem Raum voller Studierender und Tutorinnen und Tutoren begann ich nicht mit Code, sondern mit einer Geschichte: sinkende Radiohörzahlen, Sender, die still verschwinden, und die Idee, dass wir mit jedem Sender auch ein kleines Stück Menschheitsgeschichte verlieren. Ich fragte, wer im letzten Monat absichtlich Radio gehört hatte. Ein paar zögerliche Hände gingen hoch.

Ich rahmte das Ganze als Versuch, Radio jetzt interessant wirken zu lassen, nicht als Nostalgietrip.

Von dort rutschte der Vortrag in die Live-Demo. Ich spiegelte das iPhone auf die große Leinwand, öffnete RadioAtlas und ließ die Karte kurz atmen. Man sah diese dichte Galaxie aus blauen Clustern über den Globus verteilt. Gemeinsam zoomten wir nach München, tippten einen Sender an und wurden nicht von einem cineastischen Soundtrack begrüßt, sondern von einer brutal normalen deutschen Radiowerbung. Dieser Moment, in dem alle lachten, während die App schon wieder Werbung spielte, traf genau den Grund, warum ich sie gebaut habe. Es ist keine polierte, kuratierte Experience, sondern das, was gerade wirklich auf Sendung ist.

Danach zeigte ich die Funktionen in Bewegung statt als Bullet Points auf Folien. Wir sprangen von München in andere Teile der Welt, favorisierten ein paar Sender und zeigten, wie der Player uns auf den Lock Screen, ins Control Center und auf meine Apple Watch folgte. Von der Watch zu pausieren und fortzusetzen, während die große Leinwand das Now Playing-Sheet in Echtzeit aktualisierte, war eine gute visuelle Art, die Ökosystem-Integration zu demonstrieren, ohne APIs beim Namen aufzuzählen.

Das Q&A am Ende war angenehm direkt. Leute wollten wissen, wann die App in den App Store kommt, ob ich eine Android-Version bauen würde und ob sie meinen „Lieblingssender“ aus der Demo hören könnten. Ein Freund nahm mich beim Wort, also schalteten wir live ein und enthüllten den Witz: einen augenzwinkernden Sender, den wir eingerichtet hatten und der endlos die Jet2-Holiday-Werbung loopt. Der Raum brach in Lachen aus, und das Meme landete besser als jeder perfekt getimte Song.

Es gab nicht einmal eine Note, stattdessen stimmten alle Studierenden ab und RadioAtlas gewann. Das fühlte sich wie ein stärkeres Signal an, dass die Kombination aus klarer Story, solider Technik und greifbarer Demo funktioniert hatte. Nach der Präsentation kamen ein paar Leute zu mir und fragten, wie die Karte implementiert sei, ob sie die Idee für andere Domains forken könnten und ob ich darüber nachgedacht hätte, daraus ein richtiges Produkt zu machen. Selbst wenn RadioAtlas nie eine kommerzielle App wird, war genau diese Neugier und dieses Gespräch das, was ich auslösen wollte.

Fazit und was als Nächstes kommt

RadioAtlas begann als kleine Kursaufgabe und wurde am Ende zu einer ziemlich meinungsstarken Vorlage dafür, wie ich kartenlastige, ökosystembewusste iOS-Apps gerne baue. Es kombiniert eine echte Datenquelle, durchdachtes Caching, Background Jobs und tiefe Integration mit der Apple-Plattform zu etwas, das sich nicht wie eine Tech-Demo anfühlt, wenn man es jemand anderem in die Hand gibt. Vor allem verwandelte es die abstrakte Idee, „Radiokultur zu bewahren“, in etwas, durch das du buchstäblich wischen und dem du zuhören kannst.

Es gibt viele Richtungen, in die das gehen könnte: eine Jetpack Compose- oder Web-Version, damit Nicht-iOS-Freunde mitmachen können, smartere Filter für Power User, vielleicht sogar Social Features, damit Leute Sender wie Reiseempfehlungen tauschen können. Ob das jemals shippt oder nicht, das Projekt hat seinen Job für mich schon erledigt. Es hat mir viel über Systemdesign beigebracht, meine Intuition für Performance auf begrenzten Geräten gestärkt und mich daran erinnert, dass der beste Einsatz neuer Frameworks manchmal darin besteht, ein altes Medium zu feiern.

Für den Moment bin ich einfach froh, dass irgendwo da draußen ein winziger Radiosender ins Nichts sendet und RadioAtlas jemandem mit ein paar Taps auf ein Glasrechteck helfen kann, zufällig darüber zu stolpern.

Skills Improved

SwiftUI +25
iOS Development +20
SwiftData +15
MapKit +15
Apple Ecosystem +10