Cross-platform .NET MAUI 10 and Uno Platform app for AzuraCast webradio streaming.
Want to try RadioE45 before the public release? Join the preliminary tests:
- π± Android beta: https://groups.google.com/g/radioe45-testers
- π§ Linux preview (.deb, x64 and arm64): https://github.com/delfuria/RadioE45/releases
- iOS 15+
- Android 8.0+ (API 26), including Android TV and Google TV
- macOS (Mac Catalyst) 15+
- Windows 10 (build 17763+)
- Linux (preview): Debian/Ubuntu-based distributions,
.debpackage for x64 and arm64 - Web: modern desktop and mobile browsers, nothing to install (installable as an app)
- Background audio streaming (iOS: native AVPlayer for HLS and an in-app AudioQueue player for MP3/AAC streams; Android: Media3; Mac Catalyst and Windows:
CommunityToolkit.Maui.MediaElement) - Now Playing updated every 10 seconds from the AzuraCast API
- Cover art, artist, and current track title
- LIVE indicator with streamer name
- Listener count
- Player with play/pause/stop and volume control
- Station list with quick selection
- Podcast support with saved playback position (resume where you left off) and filters by season, episode, and listening status
- Song requests, when enabled by the station's AzuraCast platform
- Recently played tracks list
- Local persistence with SQLite
- Dark theme by default
- Update check: once a day, on the first launch, the app tells you when a newer version is available (App Store on iOS and Mac, Microsoft Store or GitHub Releases on Windows, GitHub Releases for the Linux
.deb, the site itself on the web), and Settings has a manual check - Apple CarPlay support (iOS)
- Android Auto support
- Web app in the browser, built with Uno Platform and installable as an app
- Android TV and Google TV support, with remote-control (D-pad) screens
Android Auto is now implemented. The Android audio layer was rebuilt: playback moved from
CommunityToolkit.Maui.MediaElement to AndroidX Media3 / ExoPlayer with a single
MediaLibraryService, enabling Android Auto, Bluetooth/AVRCP controls, and reliable
background playback. Full details (technical analysis, rebuild report, dev setup, in
Italian and English) are in docs/android-auto-media3/.
CarPlay is implemented for iOS with the CarPlay Audio entitlement. The car screen shows the
station list (CPListTemplate); choosing a station starts playback and opens Now Playing
(CPNowPlayingTemplate) with track, artist, cover art and elapsed time. Play, pause and
next/previous station work from the car controls and the iPhone lock screen. The app can be
started directly from CarPlay without opening it on the iPhone first.
Live MP3/AAC streams are played by an in-app AudioQueue player: with AVPlayer CarPlay waited
about 20 seconds before the first sound (analysis in
docs/carplay-ios/carplay-mp3-start-delay.md).
Architecture, files and test procedure: docs/carplay-ios/.
Radio E45 also runs in the browser, with no installation: open https://delfuria.github.io/RadioE45/ on a desktop or mobile browser and press Play.
The web app is built with Uno Platform (net10.0-browserwasm, WebAssembly) and
shares its logic with the native apps through RadioE45.Core: the same stations, now playing, song
requests, podcasts and schedule, with the same view models. It can also be installed as an app from the
browser menu (progressive web app), and it checks by itself when a newer version is available.
It is published automatically to GitHub Pages from main
(pages.yml). To build and run it locally see
Linux and Web (Uno Platform) below.
The Android app also runs on Android TV and Google TV, with screens designed for the remote control and for viewing from the couch. It is the same app and the same package as the phone version: on a TV it shows a dedicated interface instead of the touch one.
- On Air: cover art, title and artist, progress, listener count, the next track when the station publishes it, previous/next station and favorite
- Request: search songs with the on-screen keyboard and send a request, when the station enables it
- Podcasts: shows and episodes, with the saved position and Β±30 s seek from the D-pad, when the station has podcasts
- Schedule: the station's programs at full screen, with streamers marked by a microphone
- Channels: choose the station, and add, edit or delete stations
Everything is reachable with the D-pad (up, down, left, right, OK, Back) and the media keys of the
remote. The TV has no settings page and no side menu. Tested on the Android TV emulator and on a Sony
BRAVIA Google TV; the release package includes armeabi-v7a, needed by 32-bit TVs. Plan, measurements
and remaining decisions: docs/ANDROID-TV-ROADMAP.md.
All documentation lives in docs/:
| Topic | Path |
|---|---|
| Android Auto / Bluetooth β Media3 rebuild (IT + EN) | docs/android-auto-media3/ |
| Apple CarPlay (architecture, tests, App Store) | docs/carplay-ios/ |
| CarPlay / Android Auto β original implementation | docs/carplay/ |
UI localization (.resx) |
docs/LOCALIZATION.md |
| Store distribution | docs/STORE-DISTRIBUTION.md Β· docs/store-descriptions.md |
| Version bump procedure | docs/VERSION-BUMP.md |
| Windows build notes | docs/WINDOWS-README.md |
| App Store review 5.2.3 (third-party content, Terms of Use) | docs/APP-REVIEW-5.2.3.md |
| App Store review 5.1.1 (Local Network purpose string, private hosts) | docs/APP-REVIEW-5.1.1.md |
| Tester distribution | docs/tester/distribuzione-tester.md |
The app ships with no third-party catalog. The only stations it can add on first launch are these two; every other station is added by the user via public URL.
| Name | Server |
|---|---|
| RadioE45 (operated by the developer) | radioe45.ddns.net |
| AzuraTest Radio (official AzuraCast demo) | demo.azuracast.com |
On first launch the app also shows Terms of Use once (see docs/APP-REVIEW-5.2.3.md).
RadioE45/AppSecrets.cs contains sensitive data (e.g. the Sentry DSN) and is excluded from the repository via .gitignore. Before building, create it from the template:
cp RadioE45/AppSecrets.template.cs RadioE45/AppSecrets.csThen open AppSecrets.cs and fill in the real values:
internal static class AppSecrets
{
public const string SentryDsn = "https://..."; // your Sentry DSN
}Without this file the project will not compile. Never commit
AppSecrets.cs.
# Restore packages
dotnet restore RadioE45/RadioE45.csproj# Debug build
dotnet build -f net10.0-maccatalyst RadioE45/RadioE45.csproj
# Run on macOS
dotnet build -t:Run -f net10.0-maccatalyst RadioE45/RadioE45.csproj
# Release β universal binary (x64 + arm64, default in Release config)
dotnet publish -f net10.0-maccatalyst -c Release RadioE45/RadioE45.csproj
# Release β x64 only (Intel Mac), self-contained
dotnet publish -f net10.0-maccatalyst -c Release -r maccatalyst-x64 --self-contained RadioE45/RadioE45.csproj
# Release β arm64 only (Apple Silicon), self-contained
dotnet publish -f net10.0-maccatalyst -c Release -r maccatalyst-arm64 --self-contained RadioE45/RadioE45.csprojOutput: RadioE45/bin/Release/net10.0-maccatalyst/
In Release config the default is already a universal binary (x64 + arm64). The Mac App Store requires either both architectures or x64 only β never arm64 alone.
With--self-containedthe .NET 10 runtime is bundled in the.app; without it the target machine must have the runtime installed.
Must be built on a Windows machine.
# Release β x64, self-contained (.exe, no MSIX)
dotnet publish -f net10.0-windows10.0.19041.0 -c Release -r win-x64 --self-contained RadioE45/RadioE45.csproj
# Release β arm64, self-contained (.exe, no MSIX)
dotnet publish -f net10.0-windows10.0.19041.0 -c Release -r win-arm64 --self-contained RadioE45/RadioE45.csprojOutput: RadioE45/bin/Release/net10.0-windows10.0.19041.0/win-x64/publish/
WindowsPackageType=Noneis already set in the project, so the output is an unpackaged.exewith no MSIX wrapper.
Remove--self-contained(or pass--self-contained false) to produce a smaller, framework-dependent executable that requires .NET 10 installed on the target machine.
Requires macOS with Xcode installed. Physical device deployment requires a valid Apple Developer account.
# Debug build
dotnet build -f net10.0-ios RadioE45/RadioE45.csproj
# Release β physical device (arm64), signed
dotnet publish -f net10.0-ios -c Release -r ios-arm64 --self-contained RadioE45/RadioE45.csproj \
-p:CodesignKey="iPhone Distribution: <Your Name>" \
-p:CodesignProvision="<Provisioning Profile Name>"
# Release β simulator arm64 (Apple Silicon Mac), no signing required
dotnet publish -f net10.0-ios -c Release -r iossimulator-arm64 --self-contained RadioE45/RadioE45.csproj
# Release β simulator x64 (Intel Mac)
dotnet publish -f net10.0-ios -c Release -r iossimulator-x64 --self-contained RadioE45/RadioE45.csprojThe .NET runtime is always embedded in the
.ipabundle β--self-containedis effectively implicit for iOS.
Obtain the distribution certificate and provisioning profile from Apple Developer.
# Debug build
dotnet build -f net10.0-android RadioE45/RadioE45.csproj
# Release APK β all ABIs (arm64-v8a, armeabi-v7a, x86_64)
dotnet publish -f net10.0-android -c Release RadioE45/RadioE45.csproj
# Release APK β arm64 only (modern devices)
dotnet publish -f net10.0-android -c Release -r android-arm64 RadioE45/RadioE45.csproj
# Release APK β x64 only (emulators, Intel Chromebooks)
dotnet publish -f net10.0-android -c Release -r android-x64 RadioE45/RadioE45.csprojOutput: RadioE45/bin/Release/net10.0-android/publish/
The Mono runtime is always bundled inside the APK β
--self-containedis implicit and has no effect here.
To sign the APK for store distribution, add:-p:AndroidSigningKeyStore=key.jks \ -p:AndroidSigningKeyAlias=<alias> \ -p:AndroidSigningKeyPass=<pass> \ -p:AndroidSigningStorePass=<pass>
The Linux desktop app and the web app are built with Uno Platform from the
RadioE45.Unoproject, which shares the logic inRadioE45.Core. Build them on Linux (Ubuntu/Debian recommended) or on macOS for the desktop and web targets.
AppSecrets.csis not needed: the Uno projects do not use it.
Requirements (Ubuntu/Debian):
# System packages (libVLC for playback, X11 and fontconfig for the desktop renderer)
sudo apt update && sudo apt install -y git curl \
vlc libvlc-dev libvlc5 libx11-dev libfontconfig1 libice6 libsm6
# .NET 10 SDK (or: dotnet-install.sh --channel 10.0)
sudo apt install -y dotnet-sdk-10.0
# Uno Platform checks and WebAssembly workload (web target)
dotnet tool install -g uno.check && uno-check --target linux --non-interactive
dotnet workload install wasm-toolsPackaging a .deb also needs dpkg-deb (included in dpkg on Linux; on macOS: brew install dpkg).
# Restore packages
dotnet restore RadioE45.Uno/RadioE45.Uno.csproj
# Desktop debug build and run
dotnet build RadioE45.Uno -f net10.0-desktop
dotnet run --project RadioE45.Uno -f net10.0-desktop
# Web debug build and run (http://localhost:5045)
dotnet build RadioE45.Uno -f net10.0-browserwasm
dotnet run --project RadioE45.Uno -f net10.0-browserwasm
# Release .deb package (x64 or arm64)
packaging/linux/build-deb.sh linux-x64 <output-dir>
packaging/linux/build-deb.sh linux-arm64 <output-dir>Output: <output-dir>/radioe45_<version>_<amd64|arm64>.deb. The .deb is self-contained for .NET; libVLC and the other libraries come from the system and are declared as package dependencies.
The Windows libVLC binaries (pulled in by the Uno media player package) are excluded from the Linux publish, so the
.debstays around 40β45 MB.
The Linux package is a preview; the MAUI app remains the main app on macOS and Windows.
- Uno Platform β Linux desktop and web app (shares
RadioE45.Corewith the MAUI app) - .NET MAUI 10 β cross-platform framework
- CommunityToolkit.Mvvm β MVVM with source generators
- CommunityToolkit.Maui.MediaElement β audio streaming + background
- Refit β typed HTTP client for the AzuraCast API
- sqlite-net-pcl β local station persistence
- Uno Platform β Linux desktop and web app (shares
RadioE45.Corewith the MAUI app)