Geocoding
Two different jobs get called "search", and the SDK answers them in two different ways:
| I want to… | Use |
|---|---|
| turn an address or a place name into coordinates, offline | geocoding, on this page |
| find something in the map the user is already looking at | vector tile search |
Tile search is often the better answer for a map app: it needs no extra data, because it queries the tiles the layer already fetched. Geocoding is what you want when the query is an address, or when results must exist beyond the current view.
The CARTO geocoding endpoints are not part of this fork. Geocoding here is offline: an OSM package on the device, which you build and ship or download yourself.
Forward geocoding
Build the service, add one or more packages, then create a request and call it:
- Java
- TypeScript (NativeScript)
MassifObject geocoder = Massif.object("geocoding", "geocoder",
Spec.of("multi-osm-offline"));
geocoder.call("add", "/sdcard/geocoding/france.sqlite");
geocoder.set("language", "fr");
geocoder.set("maxResults", 10);
// Match as the user types, rather than only on a complete term.
geocoder.set("autocomplete", true);
MassifObject request = Massif.object("geocoding", "query", Spec.of("request")
.set("query", "rue de la Poste, Grenoble")
.set("projection", "EPSG:4326"));
geocoder.callAsync("calculateAddresses", results -> {
// The result is a JSON document rather than an object graph.
Log.i(TAG, results.json());
}, request);
import { create } from '@nativescript-community/ui-massifmaps/api';
const geocoder = create('geocoding', 'geocoder', { type: 'multi-osm-offline' });
geocoder.call('add', '/data/geocoding/france.sqlite');
geocoder.apply({ language: 'fr', maxResults: 10, autocomplete: true });
const request = create('geocoding', 'query', {
type: 'request',
query: 'rue de la Poste, Grenoble',
projection: 'EPSG:4326'
});
const json = await geocoder.callAsync('calculateAddresses', [request], (r) => r.json());
Never call it on the UI thread. A query walks a database; callAsync runs it on a worker and
delivers the result back.
Reverse geocoding
Same shape, a different service and a location instead of a query:
MassifObject reverse = Massif.object("geocoding", "reverse",
Spec.of("multi-osm-offline-reverse"));
reverse.call("add", "/sdcard/geocoding/france.sqlite");
MassifObject request = Massif.object("geocoding", "at", Spec.of("reverse-request")
.set("location", new double[] {5.7245, 45.1885})
.set("projection", "EPSG:4326"));
reverse.callAsync("calculateAddresses", results -> …, request);
A reverse result carries the same Address shape as a forward one — house number, street,
locality, county, country, plus category tags. The fields are listed under
Address in the value types.
The packages
An offline geocoding package is a SQLite database built from OSM data. They are not the same files as offline map packages — do not mix the two — and they are typically 10–40 % smaller than the map package for the same area.
Since the CARTO package server is gone, you build and host them yourself. add and remove take
a path, so a per-country download UI is just files on disk:
geocoder.call("add", downloadedPath);
geocoder.call("remove", supersededPath); // returns whether that package was loaded
Without a package loaded, every query returns nothing — there is no fallback to a network service.
Tuning
| Property | |
|---|---|
language | preferred language for the returned names |
maxResults | cap; the default is small |
autocomplete | prefix-match the last term, for a search-as-you-type field |
Full properties and methods: geocoding reference.