rnmapbox / maps

A Mapbox react native module for creating custom maps
MIT License
2.22k stars 838 forks source link

[v10] [Android] OfflineManager.createPack does not actually create a useable pack - offline experience is unusable for Android #2069

Closed wen-kai closed 2 years ago

wen-kai commented 2 years ago

Describe the bug
Offline downloading of packs does not work on Android, but it does work on iOS. On Android, after calling OfflineManager.createPack for multiple regions it appears there is only a single pack returned in OfflineManager.getPacks(). This pack appears to lack any metadata or identifier (name), and does not actually load the supposedly downloaded tiles when the map is rendered in the downloaded region's bounds & zoom level.

Android offline mode maps is currently an unusable experience on v10. iOS works as expected.

To Reproduce

  1. While online, call OfflineManager.createPack for a large region.
  2. Turn off Wifi / Internet.
  3. Render map with downloaded region in bounding box of viewport. (flip state.showMap to true in example below)

Actual: Empty map is rendered for downloaded region/zoom level. Expected: Map of downloaded region/zoom level is rendered.

Example:

import React from 'react';
import {StyleSheet, View} from 'react-native';
import MapboxGL from '@rnmapbox/maps';

const styles = StyleSheet.create({
    mapView: {flex: 1},
});

class BugExample extends React.Component {
    constructor(props) {
      super(props);

      this.state = {
        showMap: false, // change to true to show map
      };
    }

    async componentDidMount() {
        console.log('>>>>>>>>>>start creating pack', );
        await MapboxGL.offlineManager.createPack(
            {
                name: 'field-1', // any
                bounds: [[32.23782523101579, 46.39912398458027], [33.43887899585923, 47.041693870480955]], // any LARGE area
                styleURL: MapboxGL.StyleURL.Street,
                minZoom: 10,
                maxZoom: 12,
            },
            (pack, status) => {
                console.log('>>>>>>>>>>pack progress', pack.name, status.percentage, status.completedTileCount);
            },
            (pack, error) => {
                console.log('>>>>>>>>>>pack error', pack.name, error);
            },
        );

        // always shows a single pack without metadata nor identifier (name)
        console.log(MapboxGL.offlineManager.getPacks());
    }

    render() {
        // change showMap to true to render map when offline (wifi off / airplane mode) to test offline loading of tiles
        if (!this.state.showMap) return <View />;

        return (
            <View style={styles.mapView}>
                <MapboxGL.MapView
                    ref={(c) => (this._map = c)}
                    onPress={this.onPress}
                    style={styles.mapView}
                >
                    <MapboxGL.Camera
                        zoomLevel={10}
                        centerCoordinate={[33.43887899585923, 47.041693870480955]}
                    />
                </MapboxGL.MapView>
            </View>
        );
    }
}

export default BugExample;
}

Expected behavior
Map of downloaded region/zoom level is rendered. Downloaded Pack should include specified metadata and identifier.

Actual behavior
Empty map is rendered for the downloaded region/zoom level. getPacks() only shows a single pack which doesn't reflect the parameters of the pack.

Versions (please complete the following information):

Additional context
Works as expected on iOS.

Thank you for the awesome efforts building up this incredible library!

wen-kai commented 2 years ago

additionally it appears the following methods are not implemented for Android (https://github.com/rnmapbox/maps/blob/main/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/modules/RCTMGLOfflineModule.kt#L333).

for a useable experience it seems at least createPack and deletePack should be functional.

wen-kai commented 2 years ago

we were finally able to get createPack to consistently work for Android. a few strange observations:

  1. createPack resolves immediately rather than resolving when the download is complete. we ended up wrapping createPack in a promise that resolves when the updateProgressCallback status.state === 'complete'.
  2. packs don't actually download unless MapView is rendered prior to calling createPack. Our app allows users to download regions on a screen without a rendered Map, so as a hack we render a MapView component off-screen for non-map views.

Added implementation for deletePack for Android v10 here: https://github.com/rnmapbox/maps/pull/2074

allthetime commented 1 year ago

@wen-kai I've managed to get a single pack working offline on Android following your instructions, but I still have the issue that after re-load there is no meta-data attached to the pack. I want to download multiple packs and be able to enumerate them but the name property disappears after re-load still. Did you figure this out?