Swift framework to build KML files in Jeppesen ForeFlight friendly format.
This package provides a small, focused API for composing KML/KMZ documents suitable for importing into ForeFlight as User Map Shapes (KML). It intentionally avoids UI concerns — it gives you String KML output (or bytes) which your app can write to disk and share using the standard iOS share sheet.
- Compose
Placemarks withPoint,LineString,Polygonand derived geometry helpers (circles, arc sectors, etc.). - Create reusable styles (
Style,LineStyle,PolyStyle,IconStyle,LabelStyle) and assign them to placemarks. ForeFlightKMLBuildercollects placemarks and styles, emits a completekmlorkmzdocument.- Thread-safe —
ForeFlightKMLBuilderisSendable, so KML generation can run off the main thread. - Lightweight — no UI code.
- In Xcode: File › Add Packages...
- Enter the repository URL.
- Choose the
ForeFlightKMLpackage product and add it to your app target.
Using the example given on the ForeFlight website the below is generated using this Framework.
See /Tests/UserMapShapeTests/UserMapShapesSampleFullTest.swift
import ForeFlightKML
import GeodesySpherical
let builder = ForeFlightKMLBuilder(documentName: "Airport with ATZ")
builder.addLine(
name: "Runway 15-33",
coordinates: [Coordinate(latitude:, longitude:), Coordinate(latitude:, longitude:)],
style: PathStyle(color: .black)
)
builder.addPolygonCircle(
name: "Airport ATZ",
center: Coordinate(latitude:, longitude:),
radiusMeters: 4630,
style: PolygonStyle(outlineColor: .black, fillColor: .warning.withAlpha(0.3))
)
let buildResult = try builder.build(as: .kmz)
let url = FileManager.default.temporaryDirectory.appendingPathComponent("shapes.\(buildResult.fileExtension)")
try buildResult.data.write(to: url)
presentShareSheet(with: url)Note: ForeFlight supports importing KML/KMZ files via the iOS share sheet. See ForeFlight's docs for exact import behavior.
ForeFlightKMLBuilder is the builder for the KML/KMZ document.
- Document name can be set on
initor withsetDocumentName() - Coordinate precision can be configured with
setCoordinatePrecision(_:)(default 8, see below) - Elements can be manually added using
addPlacemark(_:) - The output is accessed by
try builder.build()
By default coordinates are written with up to 8 decimal places, with trailing zeros trimmed for cleaner output:
| Value | Output |
|---|---|
2.0 |
2.0 |
51.750188 |
51.750188 |
51.12345678 |
51.12345678 |
You can customise the precision (1–15) via the builder:
let builder = ForeFlightKMLBuilder(documentName: "Low-res demo")
.setCoordinatePrecision(4) // max 4dp, trailing zeros trimmedThe Coordinate.kmlString(precision:) method also accepts a precision parameter for standalone use.
addPointAdd a point with style.addLineAdd a line connecting multiple coordinates.addLineCircleAdd a circular line (approximated by line segments).addLineSectorAdd an arc sector line geometry.addPolygonAdd a polygon with outer boundary and optional holes.addPolygonCircleAdd a filled circular polygon.addPolygonSectorAdd a filled sector polygon (pie slice).addPolygonAnnularSectorAdd a filled annular (ring) sector polygon.addLabelAdd a text-only label placemark at a coordinate.
Type BuildResult contains:
data: Data
fileExtension: String
mimetype: String
Specific data access:
kml Dataviabuilder.build(as: .kml)kmz Dataviabuilder.build(as: .kmz)kml Stringviabuilder.kmlString()note: this can be unsafe and should only be used for debugging- KMZ (zipped KML) is required when using custom icons or using labelBadge (which uses a transparent .png under the hood).
Placemark— a Feature containing a geometry (must implementKMLElement). Optionally attach aKMLStyle.- Geometry types:
Point,Line,LineCircle,LineSector(sector of a Circle),Polygon,PolygonCircle(filled circle),PolygonSector(filled sector),PolygonAnnularSector,LinearRing. Styleand substyles:LineStyle,PolyStyle,IconStyle,LabelStyle.KMLColor— helper to create the aabbggrr color values used by KML.
Full public API surface is visible in the package sources.
- Buffer-based generation — KML is built using a single mutable
Stringbuffer rather than array concatenation, avoiding intermediate allocations. - Sendable —
ForeFlightKMLBuilderconforms toSendable, allowing KML/KMZ generation to run on a background thread for a responsive UI. - Smart compression — small documents (< 100 KB) skip DEFLATE compression in KMZ output, reducing overhead.
- Efficient geometry — circle point generation uses direct arithmetic rather than
Measurementconversions.
- Coordinates order: KML requires
longitude,latitude[,altitude]. The public API acceptsCoordinate(latitude:..., longitude:...)(fromGeodesy) and the framework emits coordinates in the KMLlon,lat[,alt]order. - Units: Distances (e.g.
LineCircle.radius) are in meters. - Angles/bearings: bearings (for arc & circle generation) are interpreted in degrees (0..360). The bearing convention is clockwise from north.
- Altitude: When you provide altitudes, the
AltitudeModeis emitted (defaults to.absolutein most geometries). - Styles:
Stylegenerates a stableidwhen provided; otherwise a UUID-based id is generated.ForeFlightKMLBuilderwill automatically register styles added viaPlacemark.
The repo contains an Example app that demonstrates building shapes and the Tests folder with unit and end to end example tests.
PRs welcome. Please include unit tests for any new behavior and update examples.
