
Introduction
AirPlay is Apple's wireless streaming protocol that lets users stream audio and video from their iOS devices to Apple TV, HomePod, and other AirPlay-compatible devices. In this post, we'll implement AirPlay functionality in a Flutter app using Pigeon for seamless communication between Flutter and native Swift code, then wire it into a beautiful audio player interface.
Prerequisites
Flutter project with iOS support
Xcode for iOS development
Basic understanding of Swift and Flutter
Audio streaming requirements (just_audio package)
Prerequisites for Pigeon
If you're not familiar with Pigeon, check out our comprehensive Pigeon guide that covers setup, configuration, and best practices for Flutter-to-native communication.
Let's start with the Pigeon API definition
First, create the Pigeon API definition that will generate our communication layer:
import 'package:pigeon/pigeon.dart';
@ConfigurePigeon(
PigeonOptions(
dartOut: 'lib/airplay_api.dart',
dartOptions: DartOptions(),
kotlinOut:
'android/app/src/main/kotlin/com/example/ios_playground/Airplay.kt',
kotlinOptions: KotlinOptions(),
swiftOut: 'ios/Runner/Airplay.swift',
swiftOptions: SwiftOptions(),
dartPackageName: 'com.example.ios_playground',
),
)
@HostApi()
abstract class AirplayApi {
void startAirplay();
void stopAirplay();
}
Key points:
@HostApi()marks this as a Flutter-to-native APIdartOut,swiftOut,kotlinOutspecify where generated files goSimple void methods for starting and stopping AirPlay
Add Pigeon to your project
Add Pigeon as a dev dependency in your pubspec.yaml:
dev_dependencies:
flutter_test:
sdk: flutter
flutter_lints: ^5.0.0
pigeon: ^26.0.1
Generate the Pigeon code
Run the Pigeon code generation command:
dart run pigeon --input pigeons/airplay_api.dart
This creates three files:
lib/airplay_api.dart- Flutter-side APIios/Runner/Airplay.swift- Swift protocol and setupAndroid Kotlin files (for completeness)
Implement the Swift AirPlay functionality
Create AirplayImplementation.swift with native AirPlay controls:
import Foundation
import AVKit
import MediaPlayer
import UIKit
class AirplayImplementation: AirplayApi {
private var routePickerView: AVRoutePickerView?
func startAirplay() throws {
DispatchQueue.main.async {
// Setup audio session for AirPlay playback
let session = AVAudioSession.sharedInstance()
do {
print("Setting audio session.....")
try session.setCategory(.playback, mode: .default, options: [.allowAirPlay])
try session.setActive(true)
} catch {
print("Failed to configure AVAudioSession: \(error)")
}
// Add AirPlay picker programmatically (hidden button)
print("Showing Airplay Picker.....")
let routePicker = AVRoutePickerView(frame: .zero)
routePicker.isHidden = true // no visible UI
UIApplication.shared.windows.first?.rootViewController?.view.addSubview(routePicker)
self.routePickerView = routePicker
// Programmatically trigger the AirPlay device selector
if let button = routePicker.subviews.compactMap({ $0 as? UIButton }).first {
button.sendActions(for: .touchUpInside)
}
}
}
func stopAirplay() throws {
DispatchQueue.main.async {
let session = AVAudioSession.sharedInstance()
do {
// Reset session so playback goes back to device speakers
try session.setActive(false, options: [.notifyOthersOnDeactivation])
} catch {
print("Failed to stop AirPlay: \(error)")
}
}
}
}
What this does:
AVAudioSessionconfiguration enables AirPlay routingAVRoutePickerViewprovides the native AirPlay device pickerProgrammatic button tap triggers the AirPlay selection UI
stopAirplay()resets audio routing back to device speakers
Register the implementation in AppDelegate
Wire the Swift implementation into your Flutter app:
import Flutter
import UIKit
@main
@objc class AppDelegate: FlutterAppDelegate {
override func application(
_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
) -> Bool {
GeneratedPluginRegistrant.register(with: self)
let airplayImplementation = AirplayImplementation()
let controller = window?.rootViewController as! FlutterViewController
AirplayApiSetup.setUp(binaryMessenger: controller.binaryMessenger, api: airplayImplementation)
return super.application(application, didFinishLaunchingWithOptions: launchOptions)
}
}
Key steps:
Create instance of
AirplayImplementationGet the Flutter view controller
Use
AirplayApiSetup.setUp()to register the implementation
Create the Flutter UI
Build a beautiful audio player with AirPlay integration. Here are the key UI components:
AirPlay button integration:
ShadButton.secondary(
onPressed: () {
AirplayApi().startAirplay();
},
child: const Icon(Icons.airplay_rounded, size: 28),
),
Audio player setup:
// Initialize audio player
late AudioPlayer _audioPlayer;
bool _isPlaying = false;
// Load audio source
await _audioPlayer.setAudioSource(
AudioSource.uri(Uri.parse('your-audio-url')),
);
Test the AirPlay functionality
Run on real iOS device
Tap the AirPlay button - native device picker appears
Select an AirPlay device - audio routes automatically
Play audio - streams to selected device
Wrap-up
We successfully implemented AirPlay functionality in Flutter using Pigeon for type-safe communication and native Swift code for AirPlay controls. The solution provides seamless audio streaming to AirPlay devices with a clean, native user experience.
The complete implementation is available in the iOS Playground repository with working examples.
Keep Fluttering 💙💙💙
About the author
Hey there! I'm Pranav Masekar, a dedicated Flutter developer who's all about crafting captivating mobile apps that not only look stunning but also deliver unforgettable user experiences. But it doesn't stop there – I'm also a passionate blogger, sharing insights and best practices within the Flutter community. By contributing to the growth and knowledge-sharing of fellow developers, I'm committed to fostering a dynamic and collaborative environment. And let's not forget my DevOps journey – as a seasoned engineer, I've got the CI/CD pipelines, infrastructure-as-code, and cloud platforms down to an art.
Comments
Join the discussionNo comments yet. Be the first to comment.
Flutter
This series focuses on Flutter app development convering major flutter concepts, Clean architecture and packages.



