Open-source iOS radio app with a SwiftUI interface. Used by 80+ apps on the App Store.
Looking for Android? See Swift Radio Android. Same station format, native Kotlin and Jetpack Compose.
Built on FRadioPlayer for streaming, metadata parsing, and iTunes album art fetching.
SwiftRadioCore package.SwiftRadioCore, with complete concurrency checking.Dependencies resolve through Swift Package Manager, so there's nothing to install before the first build.
SwiftRadio.xcodeproj in XcodeSwiftRadio/Config/Config.swift to set your stations URL, contact email, website, and other app-wide settingsSwiftRadio/Data/stations.json or host the file remotelySwiftRadio/Data/stations.json, or to the JSON you host at Config.stationsURLSwiftRadio/Images.xcassets/Stations/ and name the image set exactly like the station's imageURLEach station supports these fields:
{
"name": "Station Name",
"streamURL": "https://stream.example.com/live",
"imageURL": "station-image",
"desc": "Short tagline",
"longDesc": "Longer description for the detail screen",
"website": "https://example.com"
}
imageURL: an asset name for a bundled image, a full http(s) URL for a remote one, or an empty string to fall back to the stationImage placeholder.website: optional. The "Visit Website" row and the popup's website option appear only when it starts with http or https.longDesc: optional. Omit the key or leave it empty and the station info screen shows a default description.The template works at any catalog size, so a single-station app is mostly configuration:
stations.json and keep Config.useLocalStations = true.Config.hideNextPreviousButtons = true and leave Config.searchable = false.StationsStore.select(_:) once the catalog loads and set RootView's popupOpen to true. The one-row list stays behind the player as the back destination.logo and the station image in Images.xcassets, then edit the strings in Localizable.xcstrings.All user-facing strings are managed through Localizable.xcstrings (the String Catalog). Open it in Xcode to change the default English text or add new languages. Most views read their strings through Content.swift; a few accessibility labels in the player and toolbar use their catalog keys directly (player.next, player.seek, common.close and similar). Either way the text lives in the catalog, so a translation needs no code change.
SwiftUI owns the app's screens and navigation. AppEnvironment creates shared services for the phone and CarPlay, so both interfaces use the same station selection and playback state.
SwiftRadioCore is a local Swift package that separates playback, station catalogs, artwork and system-media integration from presentation. Its dependency boundaries let us test playback and catalog behavior without launching the UI. Small UIKit adapters remain for the popup player, marquee text, indicators and system presentations.
See the SwiftRadioCore guide for service boundaries and the architecture guide for the source map, popup flow and system controls.
Run the core tests from Packages/SwiftRadioCore using the package guide. They cover playback, catalog refresh, remote commands, Now Playing and interruptions without live streams.
The visual parity protocol covers screenshots, accessibility and UI regression commands. CI also builds both app targets and validates an unsigned archive. Physical-device audio routes, lock-screen controls and CarPlay remain separate acceptance checks.
| Library | Purpose |
|---|---|
| FRadioPlayer | Audio playback, stream metadata and artwork lookup, behind SwiftRadioCore |
| LNPopupUI | SwiftUI popup bar and expanded player |
| MarqueeLabel | Scrolling title in the expanded player |
| NVActivityIndicatorView | Playback equalizer and buffering animations |
Swift Package Manager manages these libraries. LNPopupUI also brings in LNPopupController, LNSwiftUIUtils and, through LNPopupController, LNSystemMarqueeLabel. SwiftRadioCore is included in this repository as a local package. The checked-in lockfiles record the exact resolved versions.
Contributions are welcome. Please branch off dev and open a pull request. Do not commit directly to master.
Looking for a simpler, single-station version? It skips the station list and launches straight into the player. One purchase now includes both the iOS and Android single-station projects.
All proceeds go directly toward maintaining and improving Swift Radio.
For custom work or more advanced needs, reach out to Fethi.
Built something with Swift Radio? We'd love to see it. Drop us a line at [email protected].
Swift Radio is open source and available under the MIT License.
1,392 followers · starred May 2019
3,322 followers · starred Oct 2015
1,519 followers · starred May 2024
73 followers · starred Mar 2019
Open-source iOS radio app with a SwiftUI interface. Used by 80+ apps on the App Store.
Looking for Android? See Swift Radio Android. Same station format, native Kotlin and Jetpack Compose.
Built on FRadioPlayer for streaming, metadata parsing, and iTunes album art fetching.
SwiftRadioCore package.SwiftRadioCore, with complete concurrency checking.Dependencies resolve through Swift Package Manager, so there's nothing to install before the first build.
SwiftRadio.xcodeproj in XcodeSwiftRadio/Config/Config.swift to set your stations URL, contact email, website, and other app-wide settingsSwiftRadio/Data/stations.json or host the file remotelySwiftRadio/Data/stations.json, or to the JSON you host at Config.stationsURLSwiftRadio/Images.xcassets/Stations/ and name the image set exactly like the station's imageURLEach station supports these fields:
{
"name": "Station Name",
"streamURL": "https://stream.example.com/live",
"imageURL": "station-image",
"desc": "Short tagline",
"longDesc": "Longer description for the detail screen",
"website": "https://example.com"
}
imageURL: an asset name for a bundled image, a full http(s) URL for a remote one, or an empty string to fall back to the stationImage placeholder.website: optional. The "Visit Website" row and the popup's website option appear only when it starts with http or https.longDesc: optional. Omit the key or leave it empty and the station info screen shows a default description.The template works at any catalog size, so a single-station app is mostly configuration:
stations.json and keep Config.useLocalStations = true.Config.hideNextPreviousButtons = true and leave Config.searchable = false.StationsStore.select(_:) once the catalog loads and set RootView's popupOpen to true. The one-row list stays behind the player as the back destination.logo and the station image in Images.xcassets, then edit the strings in Localizable.xcstrings.All user-facing strings are managed through Localizable.xcstrings (the String Catalog). Open it in Xcode to change the default English text or add new languages. Most views read their strings through Content.swift; a few accessibility labels in the player and toolbar use their catalog keys directly (player.next, player.seek, common.close and similar). Either way the text lives in the catalog, so a translation needs no code change.
SwiftUI owns the app's screens and navigation. AppEnvironment creates shared services for the phone and CarPlay, so both interfaces use the same station selection and playback state.
SwiftRadioCore is a local Swift package that separates playback, station catalogs, artwork and system-media integration from presentation. Its dependency boundaries let us test playback and catalog behavior without launching the UI. Small UIKit adapters remain for the popup player, marquee text, indicators and system presentations.
See the SwiftRadioCore guide for service boundaries and the architecture guide for the source map, popup flow and system controls.
Run the core tests from Packages/SwiftRadioCore using the package guide. They cover playback, catalog refresh, remote commands, Now Playing and interruptions without live streams.
The visual parity protocol covers screenshots, accessibility and UI regression commands. CI also builds both app targets and validates an unsigned archive. Physical-device audio routes, lock-screen controls and CarPlay remain separate acceptance checks.
| Library | Purpose |
|---|---|
| FRadioPlayer | Audio playback, stream metadata and artwork lookup, behind SwiftRadioCore |
| LNPopupUI | SwiftUI popup bar and expanded player |
| MarqueeLabel | Scrolling title in the expanded player |
| NVActivityIndicatorView | Playback equalizer and buffering animations |
Swift Package Manager manages these libraries. LNPopupUI also brings in LNPopupController, LNSwiftUIUtils and, through LNPopupController, LNSystemMarqueeLabel. SwiftRadioCore is included in this repository as a local package. The checked-in lockfiles record the exact resolved versions.
Contributions are welcome. Please branch off dev and open a pull request. Do not commit directly to master.
Looking for a simpler, single-station version? It skips the station list and launches straight into the player. One purchase now includes both the iOS and Android single-station projects.
All proceeds go directly toward maintaining and improving Swift Radio.
For custom work or more advanced needs, reach out to Fethi.
Built something with Swift Radio? We'd love to see it. Drop us a line at [email protected].
Swift Radio is open source and available under the MIT License.
1,392 followers · starred May 2019
3,322 followers · starred Oct 2015
1,519 followers · starred May 2024
73 followers · starred Mar 2019