I am wondering if it's possible to overlay a mbtiles file using a VectorSource and FillLayer using maplibre-react-native. Currently my setup works with a remotely hosted dataset, but not when using a .mbtiles file with a path from the documents filesystem path.
I am using Expo workflow with the dev-client, so I'd be best if it could be done without touching native files.
const downloadMbtiles = async () => {
const remoteUrl = 'my-url';
const localPath = FileSystem.documentDirectory + 'test.mbtiles';
const { status, uri } = await FileSystem.downloadAsync(remoteUrl, localPath);
console.warn(status, uri); // 200 ok
};
return (
<MapLibreGL.VectorSource
key={'maps-overlay'}
id={'maps-source'}
url={FileSystem.documentDirectory + 'test.mbtiles'}
>
<MapLibreGL.FillLayer
id={'test-overlay'}
sourceLayerID={'test-123'}
style={{
fillOpacity: 0.8,
fillColor: [
'interpolate',
['linear'],
['get', 'v'],
0,
'gold',
2,
'red',
],
}}
/>
</MapLibreGL.VectorSource>
);
To use a local
.mbtilesfile withmaplibre-react-nativein an Expo workflow without touching native code, you could try and serve the.mbtilesfile over HTTP using a local server within your app.That would involve using a library like
expo-server(or any other suitable library) to serve files locally: start a local server, serve the.mbtilesfile, and then use the local server's URL as the source URL in yourVectorSource.I see an @expo/server package, published a month ago (with a fairly recent changelog).
Try instead mbtiles-server or the more recent
tileserver-gl(npm install -g tileserver-gl).A
tileserver-gl path/to/your/test.mbtilesshould start a local server, usually accessible athttp://localhost:8080, serving tiles from your.mbtilesfile. The console output will provide the exact URL.With your tile server running, you will need to update your
maplibre-react-nativecomponent to fetch tiles from your localtileserver-glinstance. Replace theurlprop in theVectorSourcecomponent with the URL provided bytileserver-gls:Since
tileserver-glruns outside the Expo environment, there should be no compatibility issues. However, make sure your mobile device or simulator can access the local server. If testing on a physical device, your device and the server must be on the same network, and you may need to use your machine's IP address instead oflocalhost.That would mean a more integrated and seamless solution within the Expo and
maplibre-react-nativeenvironment. Unfortunately, thembtiles://protocol implementation inmaplibre-gl-jsis designed for direct access to.mbtilesfiles, which is not directly supported in a React Native (and by extension, Expo) environment due to the sandboxed nature of mobile app file systems and the React Native runtime.One theoretical approach to achieve direct
.mbtilesusage would be to develop a custom native module for React Native that implements.mbtilesfile reading and tile serving functionality directly within the app. That module could expose a method to React Native that returns tile images given x, y, and z parameters, mimicking a tile server's response but locally.But: that would require ejecting from Expo's managed workflow to add custom native code, which is what you wanted to avoid.
Another approach, not fully aligned with avoiding server setups, involves extracting the tiles from the
.mbtilesfile and bundling them with the app. That method, while also somewhat cumbersome, would allow for using the tiles directly from the filesystem. Tools likembutilor custom scripts could automate the extraction process.The main drawback is the significant increase in app size and the static nature of the tile data.
Hence, the first proposed approach, running a local server within the app (or using an embedded server that starts with the app) and accessing this server through a
WebViewcomponent. It usestileserver-glor a similar tool, running it in a way that is encapsulated within the app's environment.While this still involves a server, it is local to the app and does not require external hosting.