MOBAC XML Reference
Overview
ATAK loads map tile sources from XML files originally defined by the Mobile Atlas Creator (MOBAC) project. ATAK's UI labels these sources "Legacy" but the format is fully supported, widely used, and the primary way community map sources are distributed.
Three XML root element types are recognized by ATAK's parser
(MobacMapSourceFactory.java):
| Root element | Purpose | Typical use case |
|---|---|---|
customMapSource |
TMS / XYZ / quadkey tile servers | Most web tile services (OSM, Google, Bing, ESRI) |
customWmsMapSource |
OGC Web Map Service (WMS) | Government GIS servers, ArcGIS WMS endpoints |
customMultiLayerMapSource |
Composite of other sources | Overlay combinations (e.g., satellite + road labels) |
Each XML file must contain exactly one root element. This repository
distributes .xml files, though ATAK also recognizes .xmle (encrypted) and
.bsh (BeanShell scripted) map source formats.
customMapSource (TMS/XYZ Tiles)
Used for standard slippy-map tile servers that serve pre-rendered image tiles addressed by zoom/x/y or quadkey.
Element reference
| Element | Type | Required | Default | Description |
|---|---|---|---|---|
name |
string | yes | -- | Display name shown in ATAK map source list |
url |
string | yes | -- | Tile URL template with placeholders |
maxZoom |
integer | yes | -- | Maximum zoom level (inclusive) |
minZoom |
integer | no | 0 |
Minimum zoom level (inclusive) |
tileType |
string | no | none | Image format hint (e.g., png, jpg). Not validated by parser. |
tileUpdate |
string/integer | no | 0 |
Cache control value |
serverParts |
string | no | none | Whitespace-separated list for load balancing |
invertYCoordinate |
boolean | no | false |
Set true for TMS servers that use inverted Y (origin at bottom-left) |
backgroundColor |
hex color | no | #000000 |
Background color as #RRGGBB |
coordinatesystem |
string | no | EPSG:3857 |
Coordinate system identifier |
Full annotated example
From opentopo/opentopo_opentopomap.xml:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<customMapSource>
<name>OpenTopo - Opentopomap</name>
<minZoom>1</minZoom>
<maxZoom>17</maxZoom>
<tileType>png</tileType>
<tileUpdate>IfNoneMatch</tileUpdate>
<serverParts>a b c</serverParts>
<url>https://{$serverpart}.tile.opentopomap.org/{$z}/{$x}/{$y}.png</url>
</customMapSource>
Element-by-element:
name-- The string displayed in ATAK's map source selector. Can contain any characters including spaces, accented letters, and punctuation.url-- The tile URL template.{$serverpart}is replaced by one of the values fromserverPartson each request.{$z},{$x},{$y}are replaced with standard tile coordinates. HTML entities (e.g.,&) are unescaped by the parser.minZoom/maxZoom-- Integer zoom level bounds. Tiles will not be requested outside this range.maxZoomis required; if missing, parsing fails.tileType-- Informational tile format. The parser stores it as-is; it does not affect request behavior forcustomMapSource.tileUpdate-- See Cache Control.IfNoneMatchis a string value that does not match the\d+regex, so refreshInterval stays at0. It is only meaningful to downstream cache logic.serverParts-- See Server Load Balancing.invertYCoordinate-- Must be the exact stringtrueto enable (case-sensitive). Flips the Y tile coordinate:y = (2^zoom - 1) - y. Needed for some TMS servers where row 0 is at the bottom.backgroundColor-- Hex color string. The parser regex#[0-9A-Fa-f]is checked but the actual parsing expects at least 6 hex digits after#for a meaningful value. In practice, always use#000000or#FFFFFF.
Quadkey example
From Bing/Bing_Maps.xml:
<?xml version="1.0" encoding="UTF-8"?>
<customMapSource>
<name>Bing - Maps</name>
<minZoom>0</minZoom>
<maxZoom>20</maxZoom>
<tileType>png</tileType>
<tileUpdate>None</tileUpdate>
<url>https://r0.ortho.tiles.virtualearth.net/tiles/r{$q}.png?g=45</url>
<backgroundColor>#000000</backgroundColor>
</customMapSource>
The {$q} placeholder produces a Bing-style quadkey string. See
URL Placeholders for the algorithm.
customWmsMapSource (Web Map Service)
Used for OGC WMS endpoints. ATAK constructs the full GetMap query string
automatically -- you provide only the base URL and layer configuration.
Element reference
| Element | Type | Required | Default | Description |
|---|---|---|---|---|
name |
string | yes | -- | Display name |
url |
string | yes | -- | WMS base URL (up to and including ? or ending before query params) |
layers |
string | yes | -- | WMS layer name(s), comma-separated |
maxZoom |
integer | yes | -- | Maximum zoom level |
tileType |
string | yes | -- | PNG or JPG -- mapped to WMS FORMAT MIME type |
minZoom |
integer | no | -1 |
Minimum zoom level (note: defaults to -1, not 0) |
styles |
string | no | "" (empty) |
WMS STYLES parameter value |
version |
string | no | 1.1.1 |
WMS version (1.1.1, 1.3.0, or 1.3.1) |
coordinatesystem |
string | no | EPSG:4326 |
Coordinate system (note: WMS default is 4326, not 3857) |
aditionalparameters |
string | no | "" (empty) |
Extra query string appended verbatim to the GetMap URL |
additionalparameters |
string | no | "" (empty) |
Alternate (correct) spelling -- both accepted |
backgroundColor |
hex color | no | #000000 |
Background color |
north, south, east, west |
decimal | no | none | Geographic bounds (all four must be present to take effect) |
tileUpdate |
string/integer | no | 0 |
Cache control value |
WMS version differences
The version element controls how ATAK builds the GetMap URL:
| Version | CRS parameter | SRID 4326 value | Axis order |
|---|---|---|---|
1.1.1 (default) |
srs=EPSG:4326 |
EPSG:4326 |
x,y |
1.3.0 |
crs=CRS:84 (when SRID is 4326) |
CRS:84 |
x,y |
1.3.1 |
crs=CRS:84 (when SRID is 4326) |
CRS:84 |
x,y |
For SRIDs other than 4326 with WMS 1.3.x, the parameter is crs=EPSG:<srid>.
ATAK always emits the bbox in west,south,east,north order regardless of
version (which is technically non-compliant for WMS 1.3.0 with EPSG:4326, but
works because ATAK uses CRS:84 instead).
Generated query parameters
ATAK appends these parameters to the URL (in order):
service=WMS&request=GetMap&layers=<layers>&srs=EPSG:<srid>(orcrs=...for 1.3.x)&format=<mime>&width=256&height=256&version=<version>&styles=<styles>(empty string if not specified)- The
aditionalparameters/additionalparametersvalue (appended verbatim) &bbox=<west>,<south>,<east>,<north>
CDATA usage
WMS URLs and additional parameters often contain & and other XML-special
characters. Wrap them in <![CDATA[...]]> to avoid escaping issues:
<url><![CDATA[https://hazards.fema.gov:443/arcgis/services/public/NFHLWMS/MapServer/WMSServer?]]></url>
<aditionalparameters><![CDATA[&TRANSPARENT=TRUE&STYLES=default]]></aditionalparameters>
Alternatively, use XML entities (& for &).
Full annotated example
From basemapDE/basemapde_raster_farbe.xml:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<customWmsMapSource>
<name>basemap.de Raster, Farbe</name>
<minZoom>0</minZoom>
<maxZoom>19</maxZoom>
<tileType>PNG</tileType>
<version>1.3.0</version>
<layers>de_basemapde_web_raster_farbe</layers>
<url><![CDATA[https://sgx.geodatenzentrum.de/wms_basemapde?]]></url>
<coordinatesystem>EPSG:3857</coordinatesystem>
<aditionalparameters><![CDATA[]]></aditionalparameters>
<backgroundColor>#000000</backgroundColor>
</customWmsMapSource>
WMS example with additional parameters
From GRG/grg_FEMA_NFHL_Flood_Hazard_Zones.xml:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<customWmsMapSource>
<name>FEMA NFHL - Flood Hazard Zones (WMS)</name>
<minZoom>5</minZoom>
<maxZoom>19</maxZoom>
<tileType>PNG</tileType>
<version>1.3.0</version>
<layers>12</layers>
<url><![CDATA[https://hazards.fema.gov:443/arcgis/services/public/NFHLWMS/MapServer/WMSServer?]]></url>
<coordinatesystem>EPSG:4326</coordinatesystem>
<aditionalparameters><![CDATA[&TRANSPARENT=TRUE&STYLES=default]]></aditionalparameters>
<backgroundColor>#000000</backgroundColor>
</customWmsMapSource>
tileType mapping
The tileType value is uppercased by the parser and mapped to a WMS
FORMAT MIME type:
| tileType (case-insensitive) | WMS FORMAT |
|---|---|
PNG |
image/png |
JPG |
image/jpeg |
Other values will produce a null format MIME, which will break WMS requests.
Always use PNG or JPG.
customMultiLayerMapSource (Composite Layers)
Composites multiple map sources into a single tile by drawing them on an
Android Canvas and outputting the result as PNG.
Element reference
| Element | Type | Required | Default | Description |
|---|---|---|---|---|
name |
string | yes | -- | Display name |
layers |
container | yes | -- | Contains child customMapSource, customWmsMapSource, or customMultiLayerMapSource elements |
backgroundColor |
hex color | no | #000000 |
Background fill color drawn first |
layersAlpha |
string | no | all 1.0 |
Space-separated opacity values (0.0--1.0), one per layer |
How compositing works
- A 256x256 ARGB bitmap is created.
- The
backgroundColoris drawn as a solid fill. - Each child layer's tile is loaded and drawn in order (first layer on bottom).
- If
layersAlphais specified, each layer is drawn with the corresponding alpha value (0.0 = fully transparent, 1.0 = fully opaque). - The composite is compressed to PNG format at quality 80.
All child layers must use the same SRID. If they differ, construction
throws IllegalArgumentException.
The composite's zoom range is the union of all child layers' zoom ranges (min of all minZooms, max of all maxZooms). At any given zoom level, child layers outside their own zoom range are simply skipped.
Validation rules
nameis required; missing name throwsRuntimeException.- If
layersAlphais specified, the number of alpha values must equal the number of child layers. A mismatch throwsRuntimeException. - At least one child layer must be present in
layers.
Full annotated example
<?xml version="1.0" encoding="UTF-8"?>
<customMultiLayerMapSource>
<name>Satellite with Road Overlay</name>
<backgroundColor>#000000</backgroundColor>
<layersAlpha>1.0 0.7</layersAlpha>
<layers>
<customMapSource>
<name>Satellite Base</name>
<minZoom>0</minZoom>
<maxZoom>19</maxZoom>
<tileType>jpg</tileType>
<url>https://example.com/sat/{$z}/{$x}/{$y}.jpg</url>
</customMapSource>
<customMapSource>
<name>Road Overlay</name>
<minZoom>0</minZoom>
<maxZoom>19</maxZoom>
<tileType>png</tileType>
<url>https://example.com/roads/{$z}/{$x}/{$y}.png</url>
</customMapSource>
</layers>
</customMultiLayerMapSource>
The second layer (Road Overlay) is drawn at 70% opacity over the satellite
base. The layers container can hold any mix of the three source types,
including nested customMultiLayerMapSource elements.
URL Placeholders
The following placeholders are replaced in customMapSource URLs at tile
load time:
| Placeholder | Replaced with | Example |
|---|---|---|
{$z} |
Zoom level (integer) | 14 |
{$x} |
Tile column (integer) | 8567 |
{$y} |
Tile row (integer, top-left origin unless invertYCoordinate is true) |
5765 |
{$q} |
Bing-style quadkey string | 12031021230 |
{$serverpart} |
Next value from serverParts (round-robin) |
a |
Quadkey algorithm
The {$q} placeholder produces a quadkey string of length equal to the zoom
level. For each bit position from zoom down to 1:
- Start with digit
0. - If the corresponding bit in
xis set, add 1. - If the corresponding bit in
yis set, add 2. - Append the resulting digit (0, 1, 2, or 3) to the string.
At zoom level 3, tile (6, 2) produces quadkey "130":
| Bit position | x bit | y bit | Digit |
|---|---|---|---|
| 2 (mask=4) | 1 | 0 | 1 |
| 1 (mask=2) | 1 | 1 | 3 |
| 0 (mask=1) | 0 | 0 | 0 |
Result: "130".
This is the standard Bing Maps tile system quadkey encoding.
Server Load Balancing (serverParts)
The serverParts element distributes tile requests across multiple server
hostnames. Values are substituted into the {$serverpart} placeholder in
round-robin order (synchronized across threads).
The parser splits on whitespace only (\\s+ regex). Values separated by
commas without spaces are treated as a single server part.
Examples from this repository
Space-separated subdomains (correct usage):
<!-- From opentopo_opentopomap.xml -->
<serverParts>a b c</serverParts>
<url>https://{$serverpart}.tile.opentopomap.org/{$z}/{$x}/{$y}.png</url>
Cycles through: a, b, c
Space-separated numbers:
<!-- From michelin_osm_michelin.xml -->
<serverParts>1 2 3 4</serverParts>
<url>https://map{$serverpart}.viamichelin.com/...</url>
Cycles through: 1, 2, 3, 4
Comma-separated -- treated as a single value:
<!-- From openseamap_base_chart.xml -->
<serverParts>t1,t2,t3</serverParts>
This produces a single server part with the literal value t1,t2,t3.
Since the URL in this file uses a hardcoded hostname (t2.openseamap.org)
rather than {$serverpart}, this has no practical effect. If you intended
load balancing, use spaces: t1 t2 t3.
Empty element -- equivalent to omitting it:
<serverParts></serverParts>
An empty or whitespace-only value is ignored (the trim/length check prevents splitting).
Coordinate Systems
The coordinatesystem element sets the spatial reference ID (SRID) for the
map source.
| SRID | Name | Notes |
|---|---|---|
EPSG:3857 |
Web Mercator | Default for customMapSource. Standard for web tile services. |
EPSG:4326 |
WGS 84 | Default for customWmsMapSource. Geographic lat/lon coordinates. |
EPSG:900913 |
Web Mercator (legacy) | Alias for 3857. ATAK translates this internally via WebMercatorProjection. |
Format: Must match the regex EPSG:\d+ exactly. Values like epsg:3857
or EPSG:3857 (trailing space) will be silently ignored, leaving the default
in effect.
Element name casing
The parser matches only coordinatesystem (all lowercase). The camelCase
variant coordinateSystem is not recognized by the parser and will be
silently ignored, leaving the default SRID in effect.
Note: The repo's XSD schema accepts both spellings for compatibility with existing XML files, but only the lowercase version has any effect in ATAK.
Cache Control
The tileUpdate element controls how aggressively ATAK refreshes cached tiles.
The parser applies the regex \d+ -- only purely numeric strings are
recognized. Non-numeric values are silently ignored.
| Value | Meaning |
|---|---|
0 (or omitted) |
Never auto-refresh. Tiles are cached indefinitely in ATAK's SQLite tile database. |
| Any positive integer | Refresh interval in milliseconds (e.g., 604800000 = 1 week). |
None |
Not numeric -- ignored by parser. Equivalent to 0. |
IfNoneMatch |
Not numeric -- ignored by parser. Equivalent to 0. |
In practice, most sources in this repository use None or IfNoneMatch, both
of which result in the default refreshInterval = 0 (no automatic refresh).
The values None and IfNoneMatch may have meaning in the original MOBAC
desktop application, but ATAK's parser does not act on them.
HTTP Behavior
When ATAK fetches a tile, the following HTTP settings are applied
(from CustomMobacMapSource.configureConnection()):
| Setting | Value | Configurable? |
|---|---|---|
User-Agent header |
TAK |
No (hardcoded) |
x-common-site-name header |
Value of name element |
Automatic |
| Connect timeout | 3,000 ms | Only via Config object (not XML) |
| Read timeout | 5,000 ms | Only via Config object (not XML) |
| Caching | setUseCaches(true) |
No |
SSL / TLS
For HTTPS URLs, ATAK checks its internal certificate database
(AtakCertificateDatabase) for a CA certificate matching the server hostname.
If found, a custom SSLSocketFactory is configured with that trust store,
allowing connections to servers with custom/private CA certificates.
Authentication
ATAK uses AtakAuthenticationHandlerHTTP for HTTP authentication, which
supports up to 5 authentication retries. If the server returns HTTP 401
(Unauthorized) or 403 (Forbidden), the source is marked as auth-failed and
no further tile requests are made until clearAuthFailed() is called
(typically via ATAK's connectivity check mechanism).
Custom HTTP headers
There is no way to add custom HTTP headers via the XML file. The only
headers sent are User-Agent: TAK and x-common-site-name: <name>, plus
any headers added by the JVM's HTTP stack (Accept, Host, Connection, etc.).
Known Quirks
aditionalparameters is a typo -- and it's what the parser looks for
The WMS parser checks for both aditionalparameters (with one d) and
additionalparameters (correctly spelled). Either works. The misspelled
version comes from the original MOBAC project. Most existing WMS files in
the wild use the misspelled version.
Source: MobacMapSourceFactory.java line 380-381:
} else if (inTag.equals("additionalparameters")
|| inTag.equals("aditionalparameters"))
coordinatesystem vs coordinateSystem
Only coordinatesystem (all lowercase) is recognized by the parser. The
camelCase variant coordinateSystem is silently ignored. Some files in
this repository use the wrong casing (e.g.,
openseamap/openseamap_base_chart.xml),
which means their coordinate system setting has no effect and the default
SRID applies instead.
tileUpdate accepts both string values and integers -- but only integers have effect
The parser regex \d+ only matches purely numeric strings. String values
like None and IfNoneMatch are silently discarded, resulting in the default
refreshInterval = 0.
backgroundColor regex is too restrictive
The parser regex #[0-9A-Fa-f] matches only # followed by a single hex
digit. A standard 6-digit color like #000000 has 6 hex digits after #,
which does not match this single-character regex. This means
backgroundColor is effectively never parsed from XML in practice --
the value always falls through to the default 0 (transparent black).
Tile size is always 256
The tile size is hardcoded to 256 pixels in the factory (parseCustomMapSource
passes 256 directly). There is no XML element to change it.
tileType is not validated for customMapSource
For customMapSource, the tileType value is stored as-is and is not used to
determine request behavior. For customWmsMapSource, it is uppercased and
mapped to a MIME type (PNG to image/png, JPG to image/jpeg).
ignoreErrors is not parsed by ATAK
The ignoreErrors element appears in some XML files inherited from MOBAC, but
ATAK's parser does not look for or act on it. The XSD schema accepts it for
compatibility.
Entity references are rejected
The parser throws IOException("Entity Reference Error") if it encounters an
XML entity reference (e.g., &custom;). Standard XML entities like &
are handled by the XML parser itself before this check, so they work fine.
Custom entity definitions will cause parsing to fail.
WMS URL fixup
ATAK automatically appends ? or & to WMS URLs as needed. If your URL
has no query string, ? is appended. If it has a query string that doesn't
end with &, one is appended. You can include the trailing ? in your URL
(as most examples do) or omit it.
Quick Reference Table
All elements across all three root types, with which types they belong to:
| Element | customMapSource | customWmsMapSource | customMultiLayerMapSource | Description |
|---|---|---|---|---|
name |
required | required | required | Display name |
url |
required | required | -- | Tile URL template or WMS base URL |
maxZoom |
required | required | derived | Maximum zoom level |
minZoom |
optional (default 0) | optional (default -1) | derived | Minimum zoom level |
tileType |
optional | required | always PNG | Image format |
layers |
-- | required | -- | WMS layer name(s) |
layers (container) |
-- | -- | required | Child map source elements |
tileUpdate |
optional | optional | -- | Cache refresh interval |
serverParts |
optional | -- | -- | Load balancing server list |
invertYCoordinate |
optional | -- | -- | Flip Y axis for TMS |
backgroundColor |
optional | optional | optional | Background fill color |
coordinatesystem |
optional (default 3857) | optional (default 4326) | -- | Spatial reference |
styles |
-- | optional | -- | WMS styles parameter |
version |
-- | optional (default 1.1.1) | -- | WMS version |
aditionalparameters |
-- | optional | -- | Extra WMS query params |
additionalparameters |
-- | optional | -- | Same as above (alt spelling) |
north / south / east / west |
-- | optional | -- | Geographic bounds |
layersAlpha |
-- | -- | optional | Per-layer opacity values |
ignoreErrors |
ignored | ignored | -- | MOBAC element, not parsed by ATAK |
Validation
This repository includes an XSD schema at schema/mobac-maps.xsd
that validates all three XML root element types. CI validates every XML file
in the repository against this schema on pull requests.
To validate locally:
xmllint --noout --schema schema/mobac-maps.xsd path/to/source.xml