CarPlay apps without Apple’s blessings on a real car

Foti Dim
Foti Dim’s
Published in
9 min readJan 4, 2022

--

Self-signed CarPlay app on a real car

Developing iOS apps for CarPlay normally requires you to request specific “private” entitlements from Apple. Only then your app in entitled to appear on the CarPlay dashboard. Apple is notoriously slow in this process, and many times developers never hear back. The sad reality is that CarPlay apps are a privilege that only very few companies get to enjoy.

While the motivation behind this strict control most likely derives from driving safety concerns, it inevitably sets back roadmaps and hinders innovation. In this guide, we will review the hoops that we have to jump through in order to have our self-developed CarPlay apps running not only on the simulator but also on a real iPhone and car!

Prepare your CarPlay project

Setting up your Xcode project for CarPlay is more or less straightforward. This guide comes with starter code that you can use at your will. You can find it in the CarPlayUnleashed GitHub repo. I won’t go into details about the code that was specifically added to implement CarPlay functionality, as this is out of scope for this guide. You can find other guides that can help you with this. In this guide, we will only focus on the parts that would be different from your standard CarPlay guide and what needs to be done in order to run your app on a real car. So, git checkout the repo and follow along!

For the rest of the guide, wherever you see CarPlayUnleashed you can replace it with the name of your own app. CarPlayUnleashed is just a “sample” project.

Running on the simulator

Thankfully, running on the iOS simulator is quite straight forward. You don’t have to request any entitlements from Apple. In fact, you can add them yourself! Go to project’s target -> Signing & Capabilities -> + Capability and add any random capability, e.g. ApplePay.

This will create a “CarPlayUnleashed.entitlements” file that will automatically be added to your project.

You can now remove the ApplePay capability and open the entitlements file. There you can add the com.apple.developer.carplay-maps entry as Boolean and set the value to 1.

Of course you can pick any other CarPlay entitlement you wish. Hit The “run” button and after the simulator opens go to I/O -> External Displays -> CarPlay to open up the CarPlay simulator. Note that for CarPlay to work Siri needs to be enabled. You should now be able to see your CarPlay app running on the simulator!

Our CarPlay app running on the simulator

Running on the car

Self-signed CarPlay app on a real car

To run our app on the car we will need to install it first on a physical iPhone. Unfortunately the previous process does not work on a real device. Apple checks if the entitlements specified are included in our provisioning profile and if not signing fails.

Automatic signing fails

If you try to install the app as is, Xcode will give you an error:

Xcode refuses to build the app

Code signing the right way

Since Apple didn’t grant us the CarPlay entitlements that means we will have to go rogue!

To circumvent the above we will create a self-signed app with our own “custom” entitlements. In fact code signing was the most tricky part to figure out for this guide. You will find many methods on the wild internet on how to re-sign an app but for me none of them worked. In the best case, the resigned app ran fine on the phone but caused Springboard to crash when single time when I tried to launch it on CarPlay. It took me several attempts to figure this out and I am happy to present it to you. In a nutshell what we will do is extract the app’s default entitlements and while leaving them intact we will add the CarPlay entitlement on top.

Temporarily we have to remove the CarPlay entitlement so that we can have a successful build in the architecture of our device. Go to the project’s Build Settings and delete the Code Signing Entitlements value. You don’t need to remove the file, just the value in Build Settings. Select it and press backspace.

Build failing with CarPlay entitlement

Now try to run the app and you will see that your build succeeds again!

Build succeeding without CarPlay entitlement

Now select your iPhone in Xcode and run the app. It will succeed but it won’t show up in CarPlay since we removed the entitlement. That does not matter for now. We will use that build to re-enable CarPlay.

Adding back the entitlement

Now it is time to add the CarPlay entitlement back. Open terminal and change the current directory to that of your project.

cd YOUR_PROJECT

Using Finder go to DerivedData (~/Library/Developer/Xcode/DerivedData) and locate the project’s directory. Set a variable we named “ build” to the path of the iPhoneOS app in DerivedData. For me it was “CarPlayUnleashed-fivjjdckouidgwdhamhrwdsevsif/Build/Products/Debug-iphoneos/CarPlayUnleashed.app”

build=~/Library/Developer/Xcode/DerivedData/YOUR_PROJECT_ID/Build/Products/Debug-iphoneos/YOUR_PROJECT.app

Export all properties from embedded.mobileprovision to a file

security cms -D -i "$build/embedded.mobileprovision" > provision.plist

Set the project’s name to a variable named “name”

name=$(basename "`pwd`")

Extract the entitlements in a separate file

/usr/libexec/PlistBuddy -x -c 'Print:Entitlements' provision.plist > entitlements.plist

Merge the extracted entitlements with our custom entitlement of our Xcode project

/usr/libexec/PlistBuddy -x -c "Merge $name/$name.entitlements" entitlements.plist

Re-sign the app. Change “YOUR NAME” to however your development certificate is titled.

codesign -d --entitlements entitlements.plist -f -s "Apple Development: YOUR NAME" $build

At this point we are done. You can run this command to verify the entitlements if you wish:

codesign -d --entitlements - $build

It will print something like this:

[Dict]
[Key] application-identifier
[Value]
[String] 8R2IR57WKN.com.fotidim.CarPlayUnleashed
[Key] com.apple.developer.carplay-maps
[Value]
[Bool] true
[Key] com.apple.developer.team-identifier
[Value]
[String] 8R2IR57WKN
[Key] get-task-allow
[Value]
[Bool] true
[Key] keychain-access-groups
[Value]
[Array]
[String] 8R2IR57WKN.com.fotidim.CarPlayUnleashed

You can see that the CarPlay entitlement is listed along the rest of the default entitlements. Success!

Install the app on Device

Now we need a way to install the app on the device. For this you can use Xcode. Go to the Window menu , then Devices and Simulators, hit the + button and then locate the CarPlayUnleashed.app in DerivedData. Not so fast though since doing this will lead to an error:

Can’t install self-signed apps

This is because our app is self-signed and iOS does not like that…

Jailbreak

This is where jailbreak comes into play! We need to lift this restriction. A jailbroken device is able to run self-signed code. Currently jailbreaking is available for devices up to iOS 14. Unfortunately all my “modern” devices are updated to iOS 15 and that is unjailbreakable for now. However an iOS 15 jailbreak should be around the corner. I do have an old iPhone 5S though which is stuck on iOS 12 and that happens to be the perfect subject for my experiment! I always find it useful to keep such an old device around. It has proven to be useful in a multitude of cases and in fact I have even purchased an iPhone 3GS in 2019 just to be able to run iOS 6! 😅

I will not go into the details of how you can jailbreak your device. This is out of scope for this guide and there is plenty of info for those who want to look around. For the record I used checkra1n on my iPhone 5S running iOS 12.5.5.

Since we have to be able to run on iOS 12, we need to bump down our deployment target in our Xcode project.

Deployment target

When creating a new Xcode project with Xcode 13 the deployment target is set to 15. This is way too high for most apps as they would probably like to support older devices or users that opt out of iOS updates. iOS 12 would be a good choice since apart from allowing us to expand our user base it also gives us access to those forgotten iPhone devices that can be easily jailbroken and run self-signed code.

In order to cast an Xcode 13 project compatible with iOS 12 we need to do the following steps:

Set Deployment Target to iOS 12.0
  1. Set Deployment Target to iOS 12.0
  2. Delete Scenedelegate
  3. Delete UISceneSession Lifecycle delegate methods in App Delegate
  4. Delete SceneDelegate entry in info.plist

Without doing the above the compiler will complain. You could skip this step if you happen to have a jailbroken device running iOS 14. In my case I didn’t, so I had to fall back to iOS 12. But again, as I said, it is a good idea to support older iOS versions anyway.

Allowing self-signed apps

Even after jailbreaking trying to install the app will give you the same error as before. We will have to install AppSync Unified. This is an iOS tweak that you can find on Cydia and will allow us to install and run unsigned and self-signed apps. After the installation we can try installing the app through Xcode again and voila! Success!

CarPlayUnleased installed successfully!

We are ready now to plug our iPhone into the car. And what do you know, it works™️!

Our CarPlay app running on the car

Bonus: Run at home without a car

In case you don’t have a CarPlay enabled car you can still test the app on the next best thing from the comfort of your desk. All you need is an Android tablet and a USB CarPlay dongle for Android head units. There are multiple vendors for such devices and they cost less than $100. Instead of a head unit you install the APK the vendor provides on your android tablet. Even a cheap Kindle Fire tablet will do! Use a USB OTG adapter to connect the dongle to the tablet. Then connect your iPhone to the dongle and boom, CarPlay on Android tablet! You can even have wireless CarPlay that way!

CarPlay running on an Android tablet. Image courtesy of redmondpie.com

Apple has also recently released the CarPlay Simulator app.

CarPlay Simulator App

It is a standalone app that is part of Additional Tools for Xcode. This is supposed to act like an emulated car infotainment screen while allowing you to connect your physical iPhone device and debug your app through Xcode. However, it seems that iOS 12 devices do not appear under CarPlay Simulator at all. I tried also 2 different iOS 15 devices and on them I got the infamous “Accessory is not Supported” message on the iPhone. It seems that the CarPlay Simulator App is not ready yet for prime time.

--

--

Software craftsman — iOS📱 MachineLearning🤖 AutonomousDriving🚙 AR👓 Bass🎸 Nintendo🎮