English | 中文
A wireless CarPlay receiver for BYD DiLink head units, based on the original xcertplay, followed up to 1.4.0 by picking its fixes (see the upstream record, in Chinese).
This branch, byd-song-plus-2021, is tested in a Song PLUS 2021 (DiLink, Android 10). It adds BYD head-unit features and fixes on top of the original and translates the interface into Simplified Chinese. For the original features, MFi connection options, and build requirements, see Original project at the end.
- Download the latest
xcertplay-mobile-<version>.apkfrom Releases and install it on the head unit. Theautomotivepackage is only for Android Automotive OS head units; BYD head units do not need it. - The package name is
com.shilapi.xcertplay.bydand the launcher name is "CarPlay", so it can be installed next to the original. - Builds use a debug signing key, so every build in this series installs over the previous one.
- MFi authentication is required, for example the CH341-to-MFI adapter board. For other options, see Original project.
- The first time the MFi adapter is connected, Android asks whether to open CarPlay for this USB device. Tick the option to use it by default and confirm; it does not ask again at later power-ons.
- For wired CarPlay, the first time the iPhone is plugged in Android asks whether to open CarPlay for it. Tick "use by default for this USB device" and confirm; it does not ask again, neither at later plug-ins nor when the iPhone re-enumerates during the connection. Charging the iPhone over USB asks once as well; after that, auto-start decides whether CarPlay opens.
- Pair the iPhone with the head unit over Bluetooth, and keep the iPhone's Bluetooth and Wi-Fi on.
- Open CarPlay and tap Settings on the home screen, or swipe down with three fingers. Categories are on the left: Connection, Display, Sound, Vehicle, Advanced, Diagnostics. Tap Save at the bottom after making changes.
- Authorize head-unit ADB. The BYD features marked as needing ADB in the table below rely on it:
- Network ADB (
127.0.0.1:5555) must be enabled on the head unit; USB debugging alone is not enough. How to enable it depends on the head-unit firmware. - Open Settings → Vehicle → BYD → Head-unit ADB, tap "Check and authorize ADB", and allow the debugging prompt on the head unit.
- The result shows whether speed and battery can be read. Background use never asks again.
- Network ADB (
- Turn on the BYD features you want (below).
- Go back to the home screen; the app starts the wireless CarPlay connection by itself.
| Feature | Where | Default | Needs ADB |
|---|---|---|---|
| The iPhone's Bluetooth calls and Bluetooth music are disconnected during CarPlay and restored afterwards: calls and music go only through CarPlay and the stock phone shows no popup (no setting) | Automatic | — | No |
| Pause head-unit Wi-Fi search during CarPlay (recommended), and restrict Gaode and Baidu network location scans, to reduce stutter | Vehicle → BYD → Wireless | On | Yes |
| Allow the wired VPN automatically: wired CarPlay needs Android to allow this app a VPN, and BYD head units show the connection request dialog every time; with this on, ADB allows it beforehand and the dialog no longer appears | Vehicle → BYD → Wired | On | Yes |
| Auto-start on boot | Connection | Off | No |
| Update check: once a day on GitHub, shown on the home screen; one tap downloads and installs it (through the head unit's ADB, after which the app opens again; without ADB through the system installer, or, where Android does not allow that, from Download/xcertplay with the file manager) | Advanced → Updates | On (checks only, never installs by itself) | To install |
| A new connection method, "Existing Wi-Fi / same LAN": the head unit and the iPhone join the same router or portable Wi-Fi and the head unit creates no hotspot, so there is no channel switching to stutter on and the head unit stays online (video in the car needs that); enter that Wi-Fi's name and password in Settings; only open and WPA2 networks work, and the router must let the devices reach each other and pass mDNS; ported from DiPlay | Connection → Connection method | Off | No |
| Keep CarPlay connected while the reversing or 360 camera is shown | Automatic | — | Yes |
| Keep CarPlay connected when the screen turns, with the picture turning too (experimental): connects with a square canvas, 1920×1920 on a Song PLUS | Advanced | On | No |
| Fill the split-screen window (experimental): in the head unit split screen CarPlay fills its window, without black bars or reconnecting; needs the setting above; the window size is remembered after the first split screen and fits exactly from the next connection; after DiPlay | Advanced | Off | No |
| CarPlay dock position: automatic (driver's side in landscape, bottom in portrait), driver's side or bottom | Display | Automatic | No |
| Video on the car screen while parked (iOS 27, experimental): video sent to CarPlay on the iPhone plays on the car screen in P, and only its audio goes on once you shift out of P; the head unit downloads the video itself, and protected video such as Apple TV+ cannot play; ported from DiPlay | Vehicle → BYD → Video | Off | Yes |
| Exit CarPlay when the car is switched off and undo the head-unit changes | Automatic | — | Yes |
| Lower AC fan during CarPlay calls, to level 1–3, restored when the call ends | Vehicle → BYD → Calls | Off | Yes |
| Song on the instrument cluster; with "car lyrics" on in the music app, the current lyric line | Vehicle → BYD → Instrument cluster | Off | Yes |
CarPlay map on the cluster (experimental): the iPhone draws a second screen for the cluster (map, turn card or both), shown on the head unit display named fission_…, which the cluster shows by itself; needs that projection display to exist, works while the CarPlay screen is open; after DiPlay |
Vehicle → BYD → Cluster | Off | No |
| Vehicle speed and gear for tunnel navigation (also needs "Report location to iPhone") | Vehicle → BYD → Vehicle data | Off | Yes |
| Electric battery and range for Apple Maps (experimental) | Vehicle → BYD → Vehicle data | Off | Yes |
| Report location to iPhone: head-unit positioning with speed and satellite data | Vehicle | Off | No |
| Separate head-unit audio channels for media, navigation, and calls, with a test tone | Sound | Automatic | No |
| Steering-wheel buttons control playback; long-press the voice button for Siri | Automatic | — | No |
| Custom AirPlay icon for the return-to-car button; the default icon is the BYD wordmark in silver on graphite, one icon for day and night | Advanced | Default icon | No |
| Manufacturer and model: BYD / Song PLUS by default and rarely worth changing; after a change, forget this car on the iPhone and pair again | Advanced | BYD / Song PLUS | No |
To reduce stutter and keep calls and music on CarPlay, wireless CarPlay changes the following on the head unit. The previous state is saved first and restored afterwards:
| Change | Notes |
|---|---|
| Disconnect the iPhone's Bluetooth calls (HFP) and Bluetooth music (A2DP) | Sets the head unit's connection priority for this iPhone to off; other phones are unaffected |
| Pause the head unit's automatic Wi-Fi search | The head unit does not join saved Wi-Fi networks meanwhile |
| Gaode Auto: restrict its Wi-Fi scans and force-stop it once per connection | Stock Gaode navigation ends and is not reopened |
| Baidu network location: restrict its Wi-Fi scans without stopping it | The head unit's network location may be coarser meanwhile |
When they are restored:
- 15 s after CarPlay disconnects; reconnecting within 15 s keeps them.
- At once when the matching option is turned off, or when you exit the app from Settings.
- When the car is switched off: a BYD head unit sleeps about 10 s after the car is switched off and closes third-party apps first. CarPlay therefore exits about 2 s after the switch-off and restores everything at once (needs ADB).
- As a fallback, anything not restored at switch-off (for example the door was opened at once and the head unit slept quickly) is restored at the next power-on:
- With auto-start off: in the background, at once.
- With auto-start on: kept for 60 s and restored only if CarPlay has not connected, so the iPhone's Bluetooth does not connect only to be dropped again.
CarPlay also takes audio focus while it plays, which pauses the head unit's own media, and keeps Wi-Fi in high-performance mode during wireless sessions.
- On: CarPlay opens and connects after the head unit boots or powers on.
- Off: CarPlay does not connect at power-on, even when Android detects the MFi adapter; open the app yourself.
Export them from Settings → Diagnostics → Export logs. The files go to "Download/xcertplay":
| File | Contents |
|---|---|
xcertplay-<time>.log |
This run's log; it starts over each time CarPlay opens |
xcertplay-boot-<time>.txt |
What happened when the car was switched off and at power-on |
xcertplay-logcat-<time>.txt |
The app's own system log |
Export before exiting the app, or this run's log is lost. The logs live in /sdcard/Android/data/com.shilapi.xcertplay.byd/files/logs/.
When opening an issue, attach all three files and name the car model and head-unit software version.
- Music occasionally stutters briefly during long playback; diagnostic logging has been added.
- If the car is switched on again within 10 s of switching it off, CarPlay does not come back by itself; open it manually.
- Exit at switch-off, the power-on restore, keeping the session during reversing and location continuation are verified in a Song PLUS 2021 (1.3.3-byd.5); turning the screen without reconnecting and local certificate files are verified there too (1.3.3-byd.8). Other models have not been tested.
Build on Windows PowerShell:
$env:JAVA_HOME = "C:\Program Files\Android\Android Studio\jbr"
.\gradlew.bat :common:testDebugUnitTest :shared:testDebugUnitTest :common:lintDebug :mobile:lintDebug :automotive:lintDebug :mobile:assembleDebug :automotive:assembleDebugOn macOS or Linux:
./gradlew :common:testDebugUnitTest :shared:testDebugUnitTest :common:lintDebug :mobile:lintDebug :automotive:lintDebug :mobile:assembleDebug :automotive:assembleDebugReleases (GitHub Actions, .github/workflows/android.yml):
- A branch push runs the tests and lint and attaches debug APKs.
- A tag push builds the release APKs and publishes a release. The version name is the tag, passed as
-PreleaseVersionName=<tag>. - An annotated tag's message becomes the release notes. Create it with
git tag -a <tag> --cleanup=whitespace -F notes.md; otherwise git drops heading lines that start with#as comments. - Signing uses four secrets:
RELEASE_KEYSTORE_BASE64,RELEASE_KEYSTORE_PASSWORD,RELEASE_KEY_ALIAS,RELEASE_KEY_PASSWORD. This repository uses a debug key so that every build installs over the others. Locally, setANDROID_KEYSTORE_PATHand the related variables to sign; without them the release APKs are unsigned.
In-car findings, firmware analysis, and open verification items are in the handoff notes, docs/handoff/2026-10-05-byd-song-plus-2021.md (Chinese).
The following describes the original xcertplay and still applies to this branch.
- CarPlay host applications for Android and Android Automotive OS.
- Support for MFi chips connected through a CH341 bridge or native
/dev/i2c-Ndevices, local certificate/private-key files, and Remote MFI authentication (see the API below). - Wired and wireless CarPlay connections.
- CarPlay Ultra triggering (the protocol stack is untested/incomplete, but it can trigger the CarPlay Ultra prompt on an iPhone).
- Voice, navigation, and music multi-channel audio output mapped to the corresponding Android channels.
- Dynamic Activity resizing with automatic re-handshaking to the new resolution.
- Vehicle head-unit location reporting.
- Android 9 (API 28) support.
MFi adapter board: CH341-to-MFI. Choose the authentication method under Settings → Connection → Authentication.
Choose "Local files" under Authentication, then use the two "Choose" buttons to select the certificate and private key with Android's system document picker. The supported formats are a DER PKCS#7 certificate (.p7b) and its matching, unencrypted DER PKCS#8 private key (.pk8). The app validates that the files match before starting the phone connection and reloads them on MFI reconnect.
Store the private key in a protected location. Neither file is copied into app preferences. When the file picker grants lasting read access, only that permission and the document URI are saved.
BYD head units run their file picker ("Downloads") as the system user, and Android does not let it grant files to other apps. In that case:
- The app asks once for storage permission and reads the selected file from its path.
- It keeps a private copy in its own storage; the copy is excluded from backups.
- Choose the files from internal storage or a USB drive. Files picked from Recent and similar entries may have no path.
The Remote MFi client treats a remote service as an MFi chip for remote calls, or uses BAA authentication. Remote authentication avoids connecting a local MFi chip.
| Method | Path | Purpose | Request body | Success response | Failure response |
|---|---|---|---|---|---|
GET |
/mfi/certificate |
Get the MFi chip version, certificate type, and certificate contents; cached by the client after the first call | None | Certificate JSON | {"detail":"..."} |
POST |
/mfi/sign |
Sign the challenge | {"challenge":"...","requestId":"..."} |
{"signature":"..."} |
{"detail":"..."} |
POST |
/mfi/reset |
Request a reset of the remote MFi chip | {} |
{"detail":""} |
{"detail":"..."} |
(Optional) Standard Bearer Authentication can be used for verification.
Currently, only BAA Authentication has been tested.
| Path | Purpose |
|---|---|
common/ |
Shared CarPlay host activity, settings UI, persistence, and app resources used by both targets. |
mobile/ |
Standard Android target using the shared CarPlay host UI. Install this on BYD head units. |
automotive/ |
Android Automotive OS target with the shared host UI and advanced audio channel mapping. |
shared/ |
Car App Library code plus the CH341, I2C, MFi, iPhone, iAP2, NCM, VPN, AirPlay, media, and BYD head-unit implementations. |
- JDK 17 or newer to launch Gradle. The daemon resolves Java 25 through the Gradle toolchain.
- Android SDK Platform 37.
- Android 9 (API 28) or newer. On Android 9, Wi-Fi P2P 5 GHz mode is unavailable and LocalOnlyHotspot is used instead.
- Android NDK
28.2.13676358. - A physical USB Host/OTG Android device and MFi hardware are required for hardware validation.
Thanks to LIVI for providing important reference for this project. Thanks to the showcase project for providing important reference for the BAA authentication in this project.
Licensed under the GNU General Public License v3.0.