A lightweight, unofficial Java SDK for the Apple Maps Server API. Designed for backend/JVM apps that need server-side geocoding, search, directions, or ETA via a REST API.
This SDK automatically exchanges your long-lived Apple-issued authorization token (JWT) for short-lived access tokens and refreshes as needed.
Note: this is not MapKit (native UI SDK) or MapKit JS (web UI SDK). This project is not affiliated with Apple.
Brief - Terminal AI chat client with /locate command powered by Apple Maps Java and rendered with TUI4J.
Apple provides three primary ways to integrate Maps. This library supports #1 (Server API).
| Service | Purpose | Best for |
|---|---|---|
| Apple Maps Server API | REST HTTP API | Backend services (Java/Kotlin/Python/etc.) that need geocoding, search, directions, or ETA data without a UI. |
| MapKit | Native UI framework | iOS/macOS apps that need interactive maps. |
| MapKit JS | JavaScript UI library | Web apps that need interactive maps in the browser. |
- Java 17+
- Apple Developer Program membership (to create a Maps Identifier + private key).
- A long-lived Apple Maps authorization token (JWT). More:
docs/authorization.md.
This repo’s build uses a Gradle Java toolchain (Java 17). If you don’t have JDK 17 installed locally, Gradle will download it automatically.
dependencies {
implementation("com.williamcallahan:apple-maps-java:0.1.5")
}<dependency>
<groupId>com.williamcallahan</groupId>
<artifactId>apple-maps-java</artifactId>
<version>0.1.5</version>
</dependency>Option A (recommended): environment variable
export APPLE_MAPS_TOKEN="your-token"or via a JVM system property
java -DAPPLE_MAPS_TOKEN="your-token" -jar your-app.jarOption B (local dev for this repo): .env fallback
cp .env-example .envThen set APPLE_MAPS_TOKEN=... in .env. This repo’s Gradle build loads .env into system properties (useful for running integration tests locally). .env is ignored by git.
If your authorization token (JWT) was generated with a specific origin claim, set APPLE_MAPS_ORIGIN as well (this value is sent as the HTTP Origin header):
export APPLE_MAPS_ORIGIN="https://api.example.com"Run the live integration test suite:
./gradlew testDetail --tests com.williamcallahan.applemaps.AppleMapsITOr run a single “smoke test”:
./gradlew testDetail --tests com.williamcallahan.applemaps.AppleMapsIT.geocodeHandlesPartialAndFullAddressesOr run a one-off CLI query:
./gradlew cli --args='geocode "880 Harrison St, San Francisco, CA 94107"'More:
- Authorization/token details:
docs/authorization.md - Integration tests:
docs/tests.md - CLI usage:
docs/cli.md - More examples:
docs/usage.md
String token = System.getenv("APPLE_MAPS_TOKEN");
if (token == null || token.isBlank()) {
token = System.getProperty("APPLE_MAPS_TOKEN");
}
if (token == null || token.isBlank()) {
throw new IllegalStateException("Set APPLE_MAPS_TOKEN (env var) or APPLE_MAPS_TOKEN (system property).");
}
String origin = System.getenv("APPLE_MAPS_ORIGIN");
if (origin == null || origin.isBlank()) {
origin = System.getProperty("APPLE_MAPS_ORIGIN");
}
AppleMaps api = (origin == null || origin.isBlank())
? new AppleMaps(token)
: new AppleMaps(token, origin);
PlaceResults results = api.geocode(GeocodeInput.builder("880 Harrison St, San Francisco, CA 94107").build());
System.out.println(results);Example response (trimmed):
{
"results": [
{
"name": "880 Harrison St",
"coordinate": {
"latitude": 37.7796095,
"longitude": -122.4016725
},
"formattedAddressLines": [
"880 Harrison St",
"San Francisco, CA 94107",
"United States"
],
"structuredAddress": {
"administrativeArea": "California",
"administrativeAreaCode": "CA",
"locality": "San Francisco",
"postCode": "94107",
"subLocality": "Yerba Buena",
"thoroughfare": "Harrison St",
"subThoroughfare": "880",
"fullThoroughfare": "880 Harrison St",
"dependentLocalities": [
"Yerba Buena"
]
},
"countryCode": "US"
}
]
}This SDK provides typed wrappers for common Apple Maps Server API operations:
- Geocoding:
geocodeandreverseGeocode - Search:
search - Autocomplete:
autocomplete,resolveCompletionUrl, andresolveCompletionUrls - Directions & ETA:
directionsandetas - Places:
lookupPlace,lookupPlaces, andlookupAlternateIds
Common use case: business / startup search (name-only or name + address) via Search + Autocomplete.
- Java (server/JVM): usable from any modern JVM app (for example Spring Boot, Spring AI, Quarkus, or plain Java) as long as you run on a compatible JDK.
- Target bytecode: built for Java 17 classfiles, so consuming projects must run on JDK 17+ (including JDK 25).
- Kotlin/JVM: works like any other Maven dependency (same JVM/JDK requirement as above).
- Android: not supported as-is because this library uses
java.net.http.HttpClient(not part of the standard Android runtime). - Kotlin Multiplatform (KMP) / iOS: KMP is a popular way to write Kotlin that runs on iOS, but iOS uses Kotlin/Native (not a JVM), so it cannot consume JVM bytecode artifacts like this. To support iOS, this would need a KMP-native implementation (for example using Ktor client) and publishing a multiplatform artifact.
Apple provides free daily quotas that are currently significantly more generous than Google Maps API. But you must have a paid Apple Developer Program membership, which costs $99/year for access to all its Apple ecosystem resources. This API is Apple hardware/software agnostic.
Apple applies a daily service-call limit per membership (for example, a quota shared between MapKit JS service requests and Apple Maps Server API calls). When you exceed the daily quota, Apple responds with HTTP 429 Too Many Requests. Apple does not provide a self-serve way to purchase additional quota; for extra capacity, contact Apple via the Maps developer dashboard.
- TUI4J (a modern TUI library for Java)
- Brief (an open-source terminal AI chat app in Java)
- Other projects
