mapbox / mapbox-gl-native-ios

Interactive, thoroughly customizable maps for iOS powered by vector tiles and OpenGL
https://www.mapbox.com/mobile/
Other
210 stars 122 forks source link

Closing and reopening offline map breaks map functionality #637

Open AAverin opened 2 years ago

AAverin commented 2 years ago

Steps to reproduce

  1. Have offline map put into cache.db files for Mapbox (offline side-loading)
  2. Open the screen with map while device is offline, observe map working
  3. Close the screen with map
  4. Open the screen with map again, observe map not working
  5. Observe error in logs

    [logging] BUG IN CLIENT OF libsqlite3.dylib: database integrity compromised by API violation: vnode unlinked while in use: /private/var/mobile/Containers/Data/Application/E9F89FE6-3545-416A-A344-313E5A65A875/Library/Application Support/___/.mapbox/cache.db

Expected behavior

Offline maps are working and correctly displaying data from the database

Actual behavior

On second time screen with map opens database crashes and map doesn't display

Configuration

Mapbox SDK versions: 5.6.0 - 6.4.0 iOS/macOS versions: Any Device/simulator models: Any Xcode version: 13

AAverin commented 2 years ago

@tobrun @1ec5 Is this project maintained at all?

1ec5 commented 2 years ago

I no longer work on this map SDK or its successor, but I’ll make an observation based on https://github.com/flutter-mapbox-gl/maps/issues/703#issuecomment-961932090:

The problem seems to be that MapboxMap is holding connection to cache.db even when map is no longer displayed on the screen and should have been cleared. Installing offline tiles tries to replace cache.db with a different offline set of tiles and fails with sql error. Same thing doesn't happen on Android, replacing cache.db when app is running works fine.

Make sure you (or Flutter Mapbox GL) aren’t manually touching cache.db while the application is running. The only time you can do that safely is at the very beginning of the process, before anything related to Mapbox GL has initialized. Otherwise, the only safe way to sideload offline packs is to call -[MGLOfflineStorage addContentsOfFile:withCompletionHandler:].

/cc @mikelmaron

AAverin commented 2 years ago

@1ec5 side-loading and activating offline maps basically replaces cache.db file with a new tiles database and then expectation is that new instance of mapbox will load different tileset. This works good for the first instance of mapbox, but not for the second. And it also works fine on Android. My theory is that connection to cache.db is not properly disposed or is leaking. I have explored all the possible options myself – checked code in this repository, checked for any possible leaks in Flutter implementation and in my codebase and now I am at the stage where I need help from original devs. I have also reproduced the problem with the minimal flutter example to make sure there are no problems I have introduced in my codebase. I know flutter isn't officially supported, but it only wraps around original SDK not adding much on the top, just calling native methods through.

Some more issues that can be related: mapbox/mapbox-gl-native#16502 mapbox/mapbox-gl-native#13282 mapbox/mapbox-gl-native-ios#486