Skip to content

Integration Guide: iOS & iPadOS

brhackle edited this page Dec 15, 2025 · 3 revisions

All Bad Elf GNSS/GPS receivers are certified via Apple's Made for iOS (MFi) program, so any location-based app can use our position data via the iOS CoreLocation framework without any additional work. If your app works with the internal GPS, it works with our receivers as well.

SKU Compatibility

Model Name SKU EA Modern
(com.bad-elf.gnss)
EA Legacy
(com.bad-elf.gps)
Configuration & FW Updates
Bad Elf Flex Mini (Standard) BE-GPS-2500 NMEA (out) DNU Flex app,
USB-C to PC/Mac
Bad Elf Flex Mini (Extreme) BE-GPS-3500 NMEA (out)
RTCM (in)
DNU Flex app,
USB-C to PC/Mac
Bad Elf Flex (Standard) BE-GPS-5500 NMEA (out) DNU Flex app,
USB key w/ OTG adapter
Bad Elf Flex (Extreme) BE-GPS-6500 NMEA (out)
RTCM (in)
DNU Flex app,
USB key w/ OTG adapter
Legacy/EOL Models:
Bad Elf GNSS Surveyor BE-GPS-3300 --- NMEA (out) USB FAT drive mode
Bad Elf GPS app (iOS)
Bad Elf Pro+ BE-GPS-2300 --- NMEA (out) USB FAT drive mode
Bad Elf GPS app (iOS)
Bad Elf Pro BE-GPS-2200 --- NMEA (out) Bad Elf GPS app (iOS)
Bad Elf GPS Lightning BE-GPS-1008 --- NMEA (out) via Lightning port Bad Elf GPS app (iOS)
  • DNU - Do not use, only for legacy apps and may be disabled in future FW updates

For iOS/iPadOS app developers wanting to enable direct communications with our current or legacy GPS/GNSS receivers, follow the steps below:

Overview

  1. Send us your app bundle ID(s) via this form. We'll get your app whitelisted with Apple, and respond back to you within 1-2 days with a PPID blurb to include in your app review notes. This is required by Apple when reviewing your TestFlight and/or App Store submissions.
  2. Update your app's Info.plist to include one or both of our supported EAAccessory protocol strings. This list controls the accessories your app can access via EAAccessory.framework.
  3. Modify your app to use the EAAccessory.framework to query connected accessories and be notified when they connect/disconnect via Bluetooth. The EAAccessory object includes basic metadata including the protocol strings supported by the receiver, model name, serial number, etc. Use these values dynamically for any in-app GNSS status panels, alerts, logging, etc -- don't hardcode them in your app!
  4. When you have an EAAccessory you'd like to use, open an EASession with your desired protocol string to start communications with the hardware. When the EASession is open and ready for writing, you'll need to send a configuration message ($PBEJS or binary packet) to the hardware to get NMEA data flowing. These are documented below.
  5. Optionally, parse the $PELFID sentence sent by our receivers. This message includes some additional metadata such as the accessory nickname and a few other status flags you can't get via the EASession object.
  6. Be ready to parse whatever NMEA or other protocols are being sent by the hardware, with flexibility for different talker IDs (GP and GN), unknown/partial/corrupt NMEA messages, and unknown binary packets. Always validate checksums, confirm the NMEA timestamps match, and use $/CR/LF bytes for synchronization as needed.
  7. Handle normal lifecycle events such as the accessory appearing and disappearing, reconnects, the data stream being starved or flooded, and the GNSS lock status changing. It's a crazy place out there!
  8. If you'd like us to do some sanity testing, shoot a TestFlight invite and quick note to ios@bad-elf.com.
  9. Let us know when your app goes live and we'll be happy to promote it, add it our list of recommended apps, etc.

Supported EAAccessory protocol strings

Modern (mandatory for new integrations): com.bad-elf.gnss

Our Bad Elf Flex and Flex Mini receivers support the com.bad-elf.gnss protocol string, which will also be supported by all future Bad Elf receivers. If available on the EAAccessory object, always use this protocol first.

Add the following to your app's Info.plist file:

<key>UISupportedExternalAccessoryProtocols</key>
<array>
	<string>com.bad-elf.gnss</string>
</array>

When the EASession is open and ready for writing, you must send a PBEJS session configuration message to the accessory, containing your app's name, bundle ID, and version. This will get NMEA sentences flowing:

$PBEJS,{"method":"session","params":{"appName":"BadElfSampleGnssApp","appId":"com.bad-elf.BadElfSampleGnssApp","appVersion":"1.0","msgs":"NMEA"}}"*6A<CR><LF>

By default our receivers send the GGA, RMC, and GST sentences. Combined, these include all of the necessary position and metadata you need for a single moment in time (epoch).

$GNGGA,174132.000,3337.813638,N,11153.327844,W,1,45,0.54,469.200,M,-26.096,M,,*47
$GNRMC,174132.000,A,3337.813638,N,11153.327844,W,0.14,247.58,111225,,,A,V*1D
$GNGST,174132.000,,,,,3.974,5.220,16.077*40

To calculate horizontal accuracy in meters, use the Pythagorean theorem on fields 6 and 7 in the GST sentence. You can use field 8 as-is for vertical accuracy in meters. These values will match what you see on the Flex LCD screen or in the Bad Elf Flex app.

Legacy: com.bad-elf.gps

If your app needs to support our legacy (end-of-life) receivers, you can add support for the legacy com.bad-elf.gps protocol string as well:

<key>UISupportedExternalAccessoryProtocols</key>
<array>
	<string>com.bad-elf.gnss</string>
	<string>com.bad-elf.gps</string>
</array>

When the EASession is open, your app will need to send a binary configuration packet to the hardware to enable NMEA flow. To enable the GGA and RMC sentences, send the following bytes:

24be001105010205310132043301640d0a24be000a0100080b0d0a

The GGA and RMC sentences include everything you need for a single epoch with the exception of accuracy metadata in meters.

$GPGGA,011449.00,3337.45759,N,11154.86471,W,1,03,6.70,445.3,M,-27.5,M,,*6C
$GPRMC,011449.00,A,3337.45759,N,11154.86471,W,0.254,,111225,,,A*6E

Your app can calculate the estimated horizontal accuracy by multiplying the GGA.HDOP value (field 8) by 3.9 meters. For vertical accuracy, just double the horizontal accuracy. These values will match what is displayed on the LCD screen and in the Bad Elf GPS app.

The legacy protocol is no longer being actively maintained or supported, so your app should always use the newer com.bad-elf.gnss protocol if it's available on the detected EAAccessory. We are only whitelisting new integrations for the legacy protocol on a case-by-base basis. Please get in touch!

Pick a CoreLocation vs. External GNSS model

There are two common patterns:

  • Model #1: Auto-connect to the first external Bad Elf GNSS receiver detected, and automatically override the CoreLocation position anytime that receiver is providing a good GPS lock. This is the most user-friendly approach, and is commonly used for EFB or other consumer apps. If your app detects multiple connected receivers via EAAccessory.framework, it should pick one (and only one) and use that receiver until it disconnects. Then your app can restart the "auto-reconnect to the first receiver found" logic.
  • Model #2: Let the user pick the exact Bad Elf receiver (by serial number) they want to override CoreLocation, and only auto-connect/use that specific receiver when it's available. This approach is commonly used by GIS/survey apps where the specific receiver configuration is important, or several receivers are being used within range of each other. It also prevents the accidental usage of lower-accuracy location sources that might be coming from CoreLocation.

With both approaches, your app UI should indicate to the user which specific location source is being used (ie: Internal GPS, Bad Elf #123456, etc), and the horizontal accuracy being reported by that source.

For Model #1, your app must support a global setting for the "auto-connect via Bad Elf SDK" logic. It can be enabled by default and can be buried deep in your app settings. This setting is handy for troubleshooting, preventing conflicts with other SDK apps, and working around potential firmware, app, and iOS bugs.

Questions?

Email us at support@bad-elf.com and we'll get back to you promptly!