Keep AirPods connected on iOS 6.
iOS 6 tears the A2DP stream down when nothing is playing, and modern AirPods then drop the link. On devices without a phone stack (iPod touch), they also fall into a ~40 second disconnect loop caused by a broken HFP battery report. LegacyAir fixes both.
Two independent modules in one package:
-
Keep-alive (
legacyair.dylib, injected into SpringBoard). While any Bluetooth device is connected, SpringBoard plays a continuous LPCM buffer through a mixable playback session, so the A2DP stream never closes.Two details are load-bearing:
- The buffer is not digital silence. It carries a tone ~84 dB down,
inaudible. A zeroed buffer makes
mediaserverdreport the audio as stopped 2.93 s in, even though the player is still running, and the stream then restarts every 11 s — worse than no keep-alive at all. numberOfLoopsdoes nothing on iOS 6. Continuity comes from starting a replacement player two seconds before the current one runs out.
- The buffer is not digital silence. It carries a tone ~84 dB down,
inaudible. A zeroed buffer makes
-
XAPL patch (
legacyair-xapl.dylib, injected into BTServer). The pods send their battery level asAT+IPHONEACCEV=1,1,76without the trailing CR. iOS 6 waits for that CR forever, the pods time out after ten seconds, reconnect, hit the same wall, and drop the ACL — a disconnect roughly every 40 seconds even mid-track.The module stops them from ever sending it, by clearing the feature bitmask in the host reply:
+XAPL=iPhone,15becomes+XAPL=iPhone,00. Nothing usable is lost on an iPod: there is nowhere to display a battery level.What it patches is a string constant, not code, so there is no hardcoded address. The module searches the daemon's
__cstringsection for+XAPL=iPhone,and rewrites the two digits after the comma. A daemon without that string is left untouched. It is armv7 only because no iOS 6 device is arm64.
The XAPL module is sandboxed away from /var/mobile, so it reports through
syslog (legacyair xapl: ...) and is disabled by deleting the dylib:
rm /Library/MobileSubstrate/DynamicLibraries/legacyair-xapl.*
killall -9 BTServer
Add the Cydia source, then search for LegacyAir:
http://dev-molly.space/repo
HTTP only: iOS 6 cannot validate modern Let's Encrypt certificates. If you
previously installed Amy's ios-6-pods-hack, remove it first so the two do not
both inject into SpringBoard:
dpkg -r ios-6-pods-hack
Without Cydia, copy legacyair.deb over, dpkg -i legacyair.deb, respring. If
dpkg refuses the package, unpacking data.tar.gz into / and respringing is
equivalent.
./build.tool produces legacyair.deb with armv7 and arm64 slices. It runs on a
current Xcode and needs nothing else — no old SDK, no Theos, no downloads.
Current SDKs ship no armv7 slice and would bind the audio classes to
AVFAudio.framework, which iOS 6 does not have, so the link goes against the
hand-written stubs in stubs/. Add a stub entry whenever you import a new
symbol, and keep it to symbols that iOS 6 exports.
Create /var/mobile/.legacyair-alerts-enable and respring to get an alert for
every state change plus a per-second trail in /var/mobile/legacyair.log showing
each player's position. The flag is read once at load, so without it the logging
costs nothing.
hcitrace.c is built into build/hcitrace.dylib but is not part of the
package. It turns on BTServer's own HCI packet log (megabytes per minute). Copy
it to the device by hand when a trace is needed, and delete it afterwards.
Please open an issue if the tweak does not work. Results so far:
- AirPods Pro 3 + iPod touch 4 + iOS 6.1.6 (keep-alive and XAPL module)
- AirPods 2 + iPhone 4S + iOS 6.1.3
- AirPods 2 + iPhone 5 + iOS 6.1.4 (
meeza) - AirPods Pro 2 + iPhone 4S + iOS 6.1.3 (
BodenLaman06)
- AirPods 2 + iPhone 4S + iOS 8.4.1
- AirPods 2 + iPhone 4S + iOS 9.3.6
- AirPods 2 + iPhone 5s + iOS 7.1.2 (
meeza— loads but no improvement) - AirPods Pro + iPod touch 5 + iOS 6.1.3 (
RossDarker— fixes pausing/skipping, still drops intermittently; the XAPL module was not part of those tests)
This is a substantial rework, published as its own project. The repositories used during development:
- asentientbot/ios-6-pods-hack (Amy) — original SpringBoard keep-alive: play silence while a Bluetooth device is connected, so A2DP never goes idle.
- mikey820/AirPodsReconnectFix — an independent iOS 6 AirPods approach that was used as a reference.