rnmapbox / rnmapbox/maps

[Bug]: Local Filesystem raster tiles

Open
#3,323 1 comment 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

bug 🪲
Dominant language
Kotlin
Stars
2.9k
Forks
947
Avg merge
6d 37m
Merged PRs (30d)
1

Description

Mapbox Implementation

Mapbox

Mapbox Version

default

Platform

Android

@rnmapbox/maps version

10.1.6

Standalone component to reproduce
import React, { useEffect} from 'react';
import Mapbox from '@rnmapbox/maps';
import { StyleSheet, View, Alert } from 'react-native';
import * as FileSystem from 'expo-file-system';

const styles = StyleSheet.create({
    map: {
        width: '100%',
        height: '100%',
    }
});

const CreateOfflineMaps = () => {
    const TILE_FOLDER = `${FileSystem.documentDirectory}tiles`;
    const MAP_URL = 'http://c.tile.openstreetmap.org';

    useEffect(() => {
        const test = async () => {
            // check if a test png exists, if not then download them
            const fileInfo = await FileSystem.getInfoAsync(`${TILE_FOLDER}/1/0/0.png`)
            if (!fileInfo.exists) {
                downloadTiles();
            }
        }
        test();
    }, []);

    const downloadTiles = async () => {
        // just a few top level tiles to test
        const tiles = [{ x: 0, y: 0, z: 1 }, { x: 1, y: 1, z: 1 }, { x: 0, y: 0, z: 0 }, { x: 1, y: 0, z: 1 }, { x: 0, y: 1, z: 1 }];

        // Create directory for tiles
        for (const tile of tiles) {
            const folder = `${TILE_FOLDER}/${tile.z}/${tile.x}`
            await FileSystem.makeDirectoryAsync(folder, { intermediates: true })
        }

        // Download tiles in batches to avoid excessive promises in flight
        const BATCH_SIZE = 100

        let batch = []

        for (const tile of tiles) {
            const fetchUrl = `${MAP_URL}/${tile.z}/${tile.x}/${tile.y}.png`
            const localLocation = `${TILE_FOLDER}/${tile.z}/${tile.x}/${tile.y}.png`
            const tilePromise = FileSystem.downloadAsync(fetchUrl, localLocation)
            batch.push(tilePromise)

            if (batch.length >= BATCH_SIZE) {
                await Promise.all(batch)
                batch = []
            }
        }

        await Promise.all(batch)

        alert('Finished downloading tiles.')
    }

    // tile url here can be replace with "http://c.tile.openstreetmap.org/{z}/{x}/{y}.png" and it works fine
    const styleJSON = {
        "version": 8,
        "name": "Offline Test",
        "sources": {
            "offline": {
                "type": "raster",
                "tiles": [
                    `${FileSystem.documentDirectory}tiles/{z}/{x}/{y}.png`
                ]        
            }
        },
        "layers": [{
            "id": "test",
            "type": "raster",
            "source": "offline",
        }]
    }

    return (
        <View style={styles.container}>
            <Mapbox.MapView 
                style={styles.map}
                styleJSON={JSON.stringify(styleJSON)}
            >
            </Mapbox.MapView>
        </View>
    );
}

export default CreateOfflineMaps
Observed behavior and steps to reproduce

If you allow the tiles to be downloaded, and reload or leave and re-enter this component, the app will crash on android (development build for expo).

Here are my relevant package versions (I'm using expo):

"@rnmapbox/maps": "^10.1.6",
"expo": "^49.0.21",
"expo-file-system": "~15.4.5",
"react": "18.2.0",
"react-native": "0.72.6",
Expected behavior

Should just show the map tiles

Notes / preliminary analysis

I don't get any errors from my terminal or anything really, it simply crashes. The code works fine if you replace the tile url with an online one like "http://c.tile.openstreetmap.org/{z}/{x}/{y}.png" and it also works as expected with the downloaded tiles on iOS.

Additional links and references

I am trying to do something similar to what is done here and downloading tiles based on this tutorial (this part works great).

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start by running the supplied standalone React Native component in an Android Expo development build, using the local raster tile URL and then the online URL for comparison. Reproduce the crash after reload or re-entering the component and inspect the Android failure; done means the downloaded tiles render without crashing, matching the iOS behavior.

Written by the indexing model from the issue text.

Assessment

Tech stack
android, javascript, react-native
Domain
mobile
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.