Open AAverin opened 2 years ago
I suspect that style files are actually somewhere online and because in the implementation didFinishLoading style
and not didFinishLoadingMap
is used as a trigger that map is ready, if style is not accessible map is never ready in Flutter.
Is there a way to put styles offline too? Why doesn't this happen on Android?
Some logs that I get
2021-10-03 09:32:23.132188+0200 Runner[1843:2050389] Connection 117: received failure notification
2021-10-03 09:32:23.132224+0200 Runner[1843:2050389] Connection 117: failed to connect 1:50, reason -1
2021-10-03 09:32:23.132238+0200 Runner[1843:2050389] Connection 117: encountered error(1:50)
2021-10-03 09:32:23.132764+0200 Runner[1843:2050389] Task <5684C397-827F-4E36-8BE1-8183B6B5292F>.<11> HTTP load failed, 0/0 bytes (error code: -1009 [1:50])
2021-10-03 09:32:23.133185+0200 Runner[1843:2050391] Task <5684C397-827F-4E36-8BE1-8183B6B5292F>.<11> finished with error [-1009] Error Domain=NSURLErrorDomain Code=-1009 "The Internet connection appears to be offline." UserInfo={_kCFStreamErrorCodeKey=50, NSUnderlyingError=0x283ce7ab0 {Error Domain=kCFErrorDomainCFNetwork Code=-1009 "(null)" UserInfo={_kCFStreamErrorCodeKey=50, _kCFStreamErrorDomainKey=1}}, _NSURLErrorFailingURLSessionTaskErrorKey=LocalDataTask <5684C397-827F-4E36-8BE1-8183B6B5292F>.<11>, _NSURLErrorRelatedURLSessionTaskErrorKey=(
"LocalDataTask <5684C397-827F-4E36-8BE1-8183B6B5292F>.<11>"
), NSLocalizedDescription=The Internet connection appears to be offline., NSErrorFailingURLStringKey=https://events.mapbox.com/events/v2?access_token=s..., NSErrorFailingURLKey=https://events.mapbox.com/events/v2?access_token=..., _kCFStreamErrorDomainKey=1}
2021-10-03 09:32:29.170930+0200 Runner[1843:2050389] Connection 118: received failure notification
2021-10-03 09:32:29.170973+0200 Runner[1843:2050389] Connection 118: failed to connect 1:50, reason -1
2021-10-03 09:32:29.171003+0200 Runner[1843:2050389] Connection 118: encountered error(1:50)
2021-10-03 09:32:29.172025+0200 Runner[1843:2050389] Task <0F420101-5251-48D3-98FE-2F920E68A9A5>.<108> HTTP load failed, 0/0 bytes (error code: -1009 [1:50])
2021-10-03 09:32:29.172229+0200 Runner[1843:2050389] Task <0F420101-5251-48D3-98FE-2F920E68A9A5>.<108> finished with error [-1009] Error Domain=NSURLErrorDomain Code=-1009 "The Internet connection appears to be offline." UserInfo={_kCFStreamErrorCodeKey=50, NSUnderlyingError=0x283ce2730 {Error Domain=kCFErrorDomainCFNetwork Code=-1009 "(null)" UserInfo={_kCFStreamErrorCodeKey=50, _kCFStreamErrorDomainKey=1}}, _NSURLErrorFailingURLSessionTaskErrorKey=LocalDataTask <0F420101-5251-48D3-98FE-2F920E68A9A5>.<108>, _NSURLErrorRelatedURLSessionTaskErrorKey=(
"LocalDataTask <0F420101-5251-48D3-98FE-2F920E68A9A5>.<108>"
), NSLocalizedDescription=The Internet connection appears to be offline., NSErrorFailingURLStringKey=https://api.mapbox.com/styles/v1/mapbox/streets-v11?sku=100RqKiN39k2f64dae1bfc0b11ffe0564e296d139dc&access_token=..., NSErrorFailingURLKey=https://api.mapbox.com/styles/v1/mapbox/streets-v11?sku=100RqKiN39k2f64dae1bfc0b11ffe0564e296d139dc&access_token=..., _kCFStreamErrorDomainKey=1}
2021-10-03 09:32:30.183758+0200 Runner[1843:2050389] Connection 119: received failure notification
2021-10-03 09:32:30.184189+0200 Runner[1843:2050389] Connection 119: failed to connect 1:50, reason -1
2021-10-03 09:32:30.184308+0200 Runner[1843:2050389] Connection 119: encountered error(1:50)
2021-10-03 09:32:30.186569+0200 Runner[1843:2054072] Task <C1B164E1-921A-4EC9-987B-F867E39F8723>.<109> HTTP load failed, 0/0 bytes (error code: -1009 [1:50])
2021-10-03 09:32:30.187461+0200 Runner[1843:2050389] Task <C1B164E1-921A-4EC9-987B-F867E39F8723>.<109> finished with error [-1009] Error Domain=NSURLErrorDomain Code=-1009 "The Internet connection appears to be offline." UserInfo={_kCFStreamErrorCodeKey=50, NSUnderlyingError=0x283ca91d0 {Error Domain=kCFErrorDomainCFNetwork Code=-1009 "(null)" UserInfo={_kCFStreamErrorCodeKey=50, _kCFStreamErrorDomainKey=1}}, _NSURLErrorFailingURLSessionTaskErrorKey=LocalDataTask <C1B164E1-921A-4EC9-987B-F867E39F8723>.<109>, _NSURLErrorRelatedURLSessionTaskErrorKey=(
"LocalDataTask <C1B164E1-921A-4EC9-987B-F867E39F8723>.<109>"
), NSLocalizedDescription=The Internet connection appears to be offline., NSErrorFailingURLStringKey=https://api.mapbox.com/styles/v1/mapbox/streets-v11?sku=100RqKiN39k2f64dae1bfc0b11ffe0564e296d139dc&access_token=..., NSErrorFailingURLKey=https://api.mapbox.com/styles/v1/mapbox/streets-v11?sku=100RqKiN39k2f64dae1bfc0b11ffe0564e296d139dc&access_token=..., _kCFStreamErrorDomainKey=1}
2021-10-03 09:32:32.199082+0200 Runner[1843:2050389] Connection 120: received failure notification
2021-10-03 09:32:32.199245+0200 Runner[1843:2050389] Connection 120: failed to connect 1:50, reason -1
2021-10-03 09:32:32.199347+0200 Runner[1843:2050389] Connection 120: encountered error(1:50)
2021-10-03 09:32:32.202032+0200 Runner[1843:2050389] Task <487B69EE-224B-42B0-8E95-41AFCCA7E7A7>.<110> HTTP load failed, 0/0 bytes (error code: -1009 [1:50])
2021-10-03 09:32:32.202822+0200 Runner[1843:2050389] Task <487B69EE-224B-42B0-8E95-41AFCCA7E7A7>.<110> finished with error [-1009] Error Domain=NSURLErrorDomain Code=-1009 "The Internet connection appears to be offline." UserInfo={_kCFStreamErrorCodeKey=50, NSUnderlyingError=0x283cafdb0 {Error Domain=kCFErrorDomainCFNetwork Code=-1009 "(null)" UserInfo={_kCFStreamErrorCodeKey=50, _kCFStreamErrorDomainKey=1}}, _NSURLErrorFailingURLSessionTaskErrorKey=LocalDataTask <487B69EE-224B-42B0-8E95-41AFCCA7E7A7>.<110>, _NSURLErrorRelatedURLSessionTaskErrorKey=(
"LocalDataTask <487B69EE-224B-42B0-8E95-41AFCCA7E7A7>.<110>"
), NSLocalizedDescription=The Internet connection appears to be offline., NSErrorFailingURLStringKey=https://api.mapbox.com/styles/v1/mapbox/streets-v11?sku=100RqKiN39k2f64dae1bfc0b11ffe0564e296d139dc&access_token=..., NSErrorFailingURLKey=https://api.mapbox.com/styles/v1/mapbox/streets-v11?sku=100RqKiN39k2f64dae1bfc0b11ffe0564e296d139dc&access_token=..., _kCFStreamErrorDomainKey=1}
2021-10-03 09:32:36.212156+0200 Runner[1843:2054071] Connection 121: received failure notification
2021-10-03 09:32:36.212295+0200 Runner[1843:2054071] Connection 121: failed to connect 1:50, reason -1
2021-10-03 09:32:36.212399+0200 Runner[1843:2054071] Connection 121: encountered error(1:50)
2021-10-03 09:32:36.214260+0200 Runner[1843:2054072] Task <9E16A306-93AC-44B2-9C9C-2C5A56FEB2CF>.<111> HTTP load failed, 0/0 bytes (error code: -1009 [1:50])
2021-10-03 09:32:36.215052+0200 Runner[1843:2054072] Task <9E16A306-93AC-44B2-9C9C-2C5A56FEB2CF>.<111> finished with error [-1009] Error Domain=NSURLErrorDomain Code=-1009 "The Internet connection appears to be offline." UserInfo={_kCFStreamErrorCodeKey=50, NSUnderlyingError=0x283caad00 {Error Domain=kCFErrorDomainCFNetwork Code=-1009 "(null)" UserInfo={_kCFStreamErrorCodeKey=50, _kCFStreamErrorDomainKey=1}}, _NSURLErrorFailingURLSessionTaskErrorKey=LocalDataTask <9E16A306-93AC-44B2-9C9C-2C5A56FEB2CF>.<111>, _NSURLErrorRelatedURLSessionTaskErrorKey=(
"LocalDataTask <9E16A306-93AC-44B2-9C9C-2C5A56FEB2CF>.<111>"
), NSLocalizedDescription=The Internet connection appears to be offline., NSErrorFailingURLStringKey=https://api.mapbox.com/styles/v1/mapbox/streets-v11?sku=100RqKiN39k2f64dae1bfc0b11ffe0564e296d139dc&access_token=..., NSErrorFailingURLKey=https://api.mapbox.com/styles/v1/mapbox/streets-v11?sku=100RqKiN39k2f64dae1bfc0b11ffe0564e296d139dc&access_token=..., _kCFStreamErrorDomainKey=1}
The style itself is, of course, bundled into the offline package and should be used by default instead of loading it from the network and failing. And it seems to be used the first time map is opened, but every subsequent opening results in error
The reason behind is a leak. I will continue investigation if it's in my codebase or in mapbox for ios
Fixing the leaks, it doesn't seem to be related.
The first start of the map, when offline map loads correctly, the errors look like
mapViewDidFailLoadingMap Error Domain=MGLErrorDomain Code=-1 "The map failed to load because an unknown error occurred." UserInfo={NSLocalizedDescription=The map failed to load because an unknown error occurred., NSLocalizedFailureReason=Failed to load tile 2/2/0=>2 for source composite: The Internet connection appears to be offline.}
The second start of the screen with the map, when offline map does not display anymore correctly, errors look like:
mapViewDidFailLoadingMap Error Domain=MGLErrorDomain Code=5 "The map failed to load because the style can't be loaded." UserInfo={NSLocalizedDescription=The map failed to load because the style can't be loaded., NSLocalizedFailureReason=loading style failed: The Internet connection appears to be offline.}
Nothing changes between two screens, second screen with the map just doesn't work because it can't load style even though it's already bundled into the map database that was side-loaded.
@m0nac0 Do you have any iOS knowledge or maybe ideas why this could be happening?
Unfortunately, my iOS dev knowledge is very limited, so I'm afraid I don't have an idea of what is going on here.
@TimothySealy wrote a lot of the iOS code for this plugin, maybe he has got an idea?
I have also noticed this 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
[logging] invalidated open fd: 48 (0x11)
This gets outputed on second call to installOfflineMapTiles
method.
@TimothySealy I would really appreciate some help or input on this ticket, offline support is critical for my project release and it's the last thing that needs fixing before I can roll out the app to customers.
I have also opened https://github.com/mapbox/mapbox-gl-native-ios/issues/637 because it's highly likely issue is somewhere in original Mapbox-iOS SDK
It looks like original mapbox-gl-native-ios SDK is not in active development for the last 2 years, they have probably been working on new v10 implementation
@AAverin how did you managed to workaround this situation? I need to initialize mapbox map when offline too.
@raphaaugustosilva I didn't. I created mapbox/mapbox-gl-native-ios#637 for the original mapbox ios SDK because the error is coming from it, so it's likely that cause is also inside original SDK. Didn't get any response there yet.
Another theoretical possibility are memory leaks that are now investigated in https://github.com/tobrun/flutter-mapbox-gl/pull/706 and https://github.com/tobrun/flutter-mapbox-gl/pull/710 https://github.com/flutter/flutter/issues/91508 is tracking leaks in flutter engine itself.
All in all, I don't know how to solve this problem yet. Some input of experienced iOS developer is needed here.
@raphaaugustosilva If you will manage to reproduce the issue using original Mapbox iOS SDK sample app and post the example here, it would help greately with investigation
@AAverin thanks! Unfortunately, I am only going to use Mapbox using Flutter (Android and iOS), but my core is to work offline.
I also tried to download offline region in background with internet before opening the map for the first time without internet (using flutter mapbox downloadOfflineRegion method), but the error is the same.
Thanks for the inputs, I`ll subscribe here in order to get more updates.
It seems that database communication is implemented in the C++ layer of Mapbox.
on iOS everything is supposed to correctly destroy in dealloc
, including database connections.
This leads me to thinking again that memory leaks in the main culprit. With flutter/flutter#91508 Flutter seems to retain in memory at least one instance of the widget, including MapboxMap. If that widget was not correctly destroyed dealloc
was not invoked in the Swift implementation and database connection wasn't correctly teared down.
Another major flutter issue related to memory leaks: https://github.com/flutter/flutter/issues/79605
Debugging some more I can confirm that even if there are completely no memory leaks in Flutter code Mapbox on iOS still throws 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
That would mean that database connection is not properly cleaned either by Mapbox iOS SDK or by MapboxGL native implementation.
@tobrun Is there any way to get some insight from Mapbox developers on this topic?
I can reproduce the bug with the following minimal example.
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.
Because I have eliminated all possible issues in dart code I think problem lies in ios implementation of mapbox sdk. @tobrun is there any way Mapbox iOS devs could investigate the problem mapbox/mapbox-gl-native-ios#637?
import 'dart:math';
import 'package:flutter/material.dart';
import 'package:mapbox_gl/mapbox_gl.dart';
void main() async {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
initialRoute: "/",
onGenerateRoute: (settings) {
switch (settings.name) {
case "/":
return MaterialPageRoute(builder: (_) {
return HomePage();
});
case "/map":
return MaterialPageRoute(builder: (_) {
return MapPage();
});
default:
return MaterialPageRoute(
settings: const RouteSettings(name: "error"),
builder: (_) {
return Scaffold(
appBar: AppBar(
title: const Text("error"),
),
);
});
}
},
);
}
}
class HomePage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text("Home page"),
),
floatingActionButton: FloatingActionButton(
onPressed: () async {
// uncomment this to install offline tile
// try {
// await installOfflineMapTiles("assets/61.db");
// } catch (err) {
// print(err);
// }
await Navigator.of(context).pushNamed("/map");
},
child: const Icon(Icons.navigation),
backgroundColor: Colors.green,
),
);
}
}
class MapPage extends StatefulWidget {
@override
State<MapPage> createState() => _MapPageState();
}
class _MapPageState extends State<MapPage> {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text("Map page"),
),
body: MapboxMap(
initialCameraPosition:
const CameraPosition(target: LatLng(52.5200, 13.4050), zoom: 15),
));
}
}
This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.
Issue is still relevant and not fixed
This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.
Issue is still relevant and not fixed downstream
Hi, I faced the same problem. Is there any workaround?
@BartoszStasiurka If issue is still there, then probably it is related to some problem in the underlying mapbox ios sdk and it won't be fixed. New official Mapbox plugin can be found here: https://pub.dev/packages/mapbox_maps_flutter Offline is not yet supported as far as I know, but they do accept feature requests
@AAverin we are using this package in production for Android. Our customer is asking after an iOS port. Is this issue still a known issue? We run mostly offline so if it is likely to crash we need to advise them to wait on mapbox_maps_flutter.
@raphael-bmec-co I have removed offline support from my product for now and didn't test since then. New official mapbox still doesn't support offline and I couldn't get any official feedback from Mapbox on the roadmap and plans. You can try asking in their Discord server. But for me it doesn't look like Mapbox is investing into Flutter, so if you need offline, best bet would be to use community plugins and serve your own tiles instead of mapbox.
Thanks @AAverin. Appreciate the feedback.
Neither
onMapReady
noronStyleLoaded
are not called when device is offline