Building Quality iOS Apps, Quickly
iOS MacAt Big Nerd Ranch, we take pride in building quality apps for our clients. Unfortunately, quality isn't the only concern when building an app...
How can you detect when the user connects their phone to their car’s stereo? This simple question that came up during a feature brainstorm session proved to have a surprisingly complicated answer. Let’s dive in.
Audio on iOS is mostly handled by the OS itself. You communicate your intent to play audio by telling an instance of AVAudioSession
(usually its singleton sharedInstance()
).
Most important for this discussion, are the available audio routes on the shared AVAudioSession
instance. Each audio route is either an input that’s receiving audio (like the phone’s microphone) or an output where we’re sending audio (like the phone’s speaker or a bluetooth headset). We can access the shared AVAudioSession
’s current route, and inspect all of its outputs:
let audioSession = AVAudioSession.sharedInstance() audioSession.currentRoute.outputs.forEach { output in print(output.portName) }
Each output is of type AVAudioSessionPortDescription
. Conveniently, in addition to each port having a name, it also has a type that’s one of these AVAudioSession.Port
values. Among them is a convenient value called carAudio
.
So! This should be easy! Monitor for changes to the ports in the shared audio session, and when we see one of type .carAudio
, then we’re connected to a car!
Turns out, there are a lot of ways to connect your iPhone to your car’s stereo:
Do these all report as .carAudio
? Can we distinguish connecting to a car via bluetooth from connecting to AirPods? Can we distinguish between a lighting connection to EarPods and a lightning connection to a car?
To answer these questions, we built a little test app and passed it around the office. The app is pretty simple:
AVAudioSession.routeChangeNotification
sYou can experiment with the app yourself by downloading it here.
Here’s a quick table of our results, showing the type of connection, if it’s actually a connection to a car, and the port’s portType
value:
Connection | Car? | Port Type |
---|---|---|
After-market bluetooth-to-aux device | Yes | .bluetoothA2DP |
Bose Bluetooth headphones | No | .bluetoothA2DP |
AirPods | No | .bluetoothA2DP |
Direct connection to car’s bluetooth | Yes | .bluetoothA2DP |
Lightning-to-headphone adapter + aux | Yes | .headphones |
Lightning EarPods | No | .headphones |
iPhone to Car’s USB port | Yes | .usbAudio |
Screen mirror to Apple TV | No | .airPlay |
Bluetooth to a CarPlay-enabled car | Yes | .carAudio |
We finally saw a .carAudio
value, but only when directly connected to a CarPlay-enabled car. Even cars with native bluetooth support reported the connection as .bluetoothA2DP
— just like any other bluetooth speaker.
However, these bluetooth connections do provide useful data. Each .bluetoothA2DP
connection also provides an identifiable name and a unique ID. Rather than automatically connect to all cars with bluetooth support, we discovered it would be possible for the user to identify a specific bluetooth device (such as their car) they’re already connected to and the app would know whenever the user connects to that device again. That will have to do for now.
At Big Nerd Ranch, we take pride in building quality apps for our clients. Unfortunately, quality isn't the only concern when building an app...
Automate your build and deploy process with fastlane and CircleCI! We'll build on our fastlane commands from Part 1 and show how to configure...
Automate your build and deploy process with fastlane and CircleCI! In this first part, we'll describe our current process and illustrate how we can...