as the subject suggests i have a problem on the app i have made with the backgroundmaps not showing on older models. The background maps comes from a group on an agol organisation https://danmarksdata.maps.arcgis.com/home/group.html?sortField=modified&sortOrder=desc&id=1a2896d741.... i use http calls to the rest api to find the items in the group and then uses:
the newest version of android where is fails has been android 13 api 33-ext5.
has any one else experienced something like this and has a solution to this.
Solved! Go to Solution.
Short answer
This is a TLS trust‑store issue on older Android builds. Your basemaps ultimately hit https://services.datafordeler.dk, whose current certificate chain (Sectigo “Public Server Authentication” hierarchy) isn’t in the system trust store on some older devices, so Android rejects the handshake. On newer OS versions the chain is trusted, so everything works. [sectigo.com], [developer....ndroid.com]
The ArcGIS Maps SDK for Flutter surfaces this as a NetworkAuthenticationChallenge. Handle the ServerTrustAuthenticationChallenge and explicitly trust that host at runtime.
The SDK lets you register a NetworkAuthenticationChallengeHandler. When the device doesn’t trust a server cert, you’ll receive a ServerTrustAuthenticationChallenge; respond with a ServerTrustNetworkCredential to trust just that host and retry the request.
Scope & safety: This trusts only the host you specify and only inside your app (not system‑wide). It’s a standard, supported workflow in the ArcGIS Maps SDK. [developers...arcgis.com]
Code (Flutter / Dart):
import 'dart:async'; import 'package:flutter/material.dart'; import 'package:arcgis_maps/arcgis_maps.dart'; // 1) (Optional) Persist network credentials across launches. Future<void> initAuthStores() async { await ArcGISEnvironment.authenticationManager.setNetworkCredentialStore( await NetworkCredentialStore.initPersistentStore(), ); // persists in Android Keystore / iOS Keychain } Future<void> main() async { WidgetsFlutterBinding.ensureInitialized(); await initAuthStores(); // Set your API key here... runApp(const MyApp()); } class MyApp extends StatelessWidget { const MyApp({super.key}); @override Widget build(BuildContext context) => const MaterialApp(home: MapPage()); } class MapPage extends StatefulWidget { const MapPage({super.key}); @override State<MapPage> createState() => _MapPageState(); } class _MapPageState extends State<MapPage> implements NetworkAuthenticationChallengeHandler { @override void initState() { super.initState(); // 2) Register this instance as the global network challenge handler. ArcGISEnvironment.authenticationManager.networkAuthenticationChallengeHandler = this; } @override FutureOr<void> handleNetworkAuthenticationChallenge( NetworkAuthenticationChallenge challenge) { // 3) Trust services.datafordeler.dk only when the OS doesn't trust its cert. if (challenge is ServerTrustAuthenticationChallenge && challenge.host == 'services.datafordeler.dk') { challenge.continueWithCredential( ServerTrustNetworkCredential.forChallenge(challenge), ); return; } // For other challenges (Basic/Digest/NTLM/Client cert), handle as needed // or fail so the error surfaces: challenge.continueAndFail(); } @override Widget build(BuildContext context) { return Scaffold( body: ArcGISMapView( controllerProvider: () => ArcGISMapView.createController() ..arcGISMap = ArcGISMap.withBasemapStyle(BasemapStyle.arcGISTopographic), ), ); } }
If you use a toolkit-based authenticator instead of handling the API directly, the toolkit also includes UI and handling for server‑trust prompts. [developers...arcgis.com]
This kind of “basemap shows on some devices but not others” issue with Flutter + ArcGIS usually boils down to one of a few culprits:
Quick things to verify first
1. Are you using http anywhere?
On Android 9+ (API 28+), cleartext (http) is blocked by default. If you call the REST API over http or if the basemap’s service URL is `http`, Android 13 will refuse to load it.
Fix: Use https everywhere for:
<!-- AndroidManifest.xml -->
<application
android:usesCleartextTraffic="true"
android:networkSecurityConfig="@xml/network_security_config" .../>
<!-- res/xml/network_security_config.xml -->
<network-security-config>
<base-config cleartextTrafficPermitted="true" />
</network-security-config>2. Check the actual load error:
Wrap loads in try/catch and print loadError.message and loadError.additionalInfo. With the ArcGIS Flutter plugin (which wraps the native SDK), you can do:
final item = PortalItem.withPortalAndItemId(portal: dataMarksPortal , itemId: dataMarksBasemapId);
await item.load();
if (item.loadStatus != LoadStatus.loaded) {
print('PortalItem failed: ${item.loadError?.message}');
}
final basemap = Basemap.withItem(item);
await basemap.load();
if (basemap.loadStatus != LoadStatus.loaded) {
print('Basemap failed: ${basemap.loadError?.message}');
}
You’ll often see something explicit like “CLEARTEXT not permitted”, “401/403”, or a TLS/certificate error.
hello Harish.
i allready use Https everywhere as it is an AGOL organisation.
i have tried the suggested error handling to check for load error, and i get no load error.
i have included a screenshot to show the problem as you can see the basemaps are loaded in the app they just show up as blanks with used in the app.
It work in newer versions.
if i need to add more information please just say what you need 🙂
best regards Rasmus
Thanks for the extra details and the screenshot, Rasmus – that’s helpful.
To dig deeper we’ll need a small reproducible example and some device specifics, so we can try to reproduce this on our side. Could you share:
1. Minimal code sample
- A pared-down widget or sample app that:
- Creates the Basemap from your AGOL group (including the Basemap.withItem(basemapItem.results[0]) part).
- Sets up the ArcGISMap / ArcGISMapView exactly as you do in your app.
- If possible, please strip it down to the smallest example that still shows the “blank basemap on older devices” behavior.
2. Device and OS details
For at least one device where it fails and one where it works:
- Device model and manufacturer (e.g. Samsung A52, Pixel 4a, etc.).
- Android version (e.g. Android 13, API 33-ext5) and whether it’s physical or emulator.
- CPU architecture (ARM64 vs x86, if you know it).
- App build type (debug/release) and whether you see the issue in both.
3. SDK / tooling versions
- ArcGIS Maps SDK for Flutter version.
- Flutter version (flutter --version).
- Your app’s minSdkVersion, targetSdkVersion, and compileSdkVersion.
Once we have a minimal repro and those details, we can try to reproduce this under the same conditions and get back to you with further updates.
1. i have attached a file with code
2. Samsung s20 Ultra, Android version 13
i run a virtuel device on android 13-0 pixel 7 where the error also happens .
it work on a device that runs android 16
i see the issue in both the debug version and the released version
3. flutter sdk version arcgis_maps: ^200.8.0+4672
flutter version 3.38.5
minsdk 28,
targetSDKversion = targetSdk = flutter.targetSdkVersion i think it is version 34,
compiledSdk is 36
Hi — thanks for the detailed report and for sharing the AGOL group you’re using.
I investigated this on my side and was able to reproduce the issue on older Android devices. The basemaps fail to draw, and the runtime repeatedly reports 401 authentication errors when it tries to access layers hosted on:
services.datafordeler.dk
On newer Android versions the same WebMaps load without errors, which initially seems odd — but there is a likely explanation:
Older Android builds often ship with outdated or missing CA root certificates.
If the certificate chain for services.datafordeler.dk isn’t trusted on that OS version, the TLS handshake can fail or degrade in a way that results in authentication failures (401) instead of a clean SSL error. Newer devices include updated CA bundles, so the same service appears to work even without explicitly handling authentication.
Since I don’t have access to your organization’s Datafordeler certificates or authentication setup, I can’t reproduce a successful connection here — but the behavior I’m seeing is consistent with a CA trust issue combined with the service requiring credentials.
I tested on:
I’m attaching the Logcat output from both runs. The Android 9 device shows repeated authentication errors, while the newer device does not.
To confirm that the issue on your device matches what I’m seeing, could you please share:
A Logcat capture from one of the older devices where the basemap fails to load
(from app start → first map draw)
Your Logcat will tell us whether:
Once we have that, we can determine whether the fix is:
Happy to continue helping — just attach the Logcat and we’ll go from there.
Short answer
This is a TLS trust‑store issue on older Android builds. Your basemaps ultimately hit https://services.datafordeler.dk, whose current certificate chain (Sectigo “Public Server Authentication” hierarchy) isn’t in the system trust store on some older devices, so Android rejects the handshake. On newer OS versions the chain is trusted, so everything works. [sectigo.com], [developer....ndroid.com]
The ArcGIS Maps SDK for Flutter surfaces this as a NetworkAuthenticationChallenge. Handle the ServerTrustAuthenticationChallenge and explicitly trust that host at runtime.
The SDK lets you register a NetworkAuthenticationChallengeHandler. When the device doesn’t trust a server cert, you’ll receive a ServerTrustAuthenticationChallenge; respond with a ServerTrustNetworkCredential to trust just that host and retry the request.
Scope & safety: This trusts only the host you specify and only inside your app (not system‑wide). It’s a standard, supported workflow in the ArcGIS Maps SDK. [developers...arcgis.com]
Code (Flutter / Dart):
import 'dart:async'; import 'package:flutter/material.dart'; import 'package:arcgis_maps/arcgis_maps.dart'; // 1) (Optional) Persist network credentials across launches. Future<void> initAuthStores() async { await ArcGISEnvironment.authenticationManager.setNetworkCredentialStore( await NetworkCredentialStore.initPersistentStore(), ); // persists in Android Keystore / iOS Keychain } Future<void> main() async { WidgetsFlutterBinding.ensureInitialized(); await initAuthStores(); // Set your API key here... runApp(const MyApp()); } class MyApp extends StatelessWidget { const MyApp({super.key}); @override Widget build(BuildContext context) => const MaterialApp(home: MapPage()); } class MapPage extends StatefulWidget { const MapPage({super.key}); @override State<MapPage> createState() => _MapPageState(); } class _MapPageState extends State<MapPage> implements NetworkAuthenticationChallengeHandler { @override void initState() { super.initState(); // 2) Register this instance as the global network challenge handler. ArcGISEnvironment.authenticationManager.networkAuthenticationChallengeHandler = this; } @override FutureOr<void> handleNetworkAuthenticationChallenge( NetworkAuthenticationChallenge challenge) { // 3) Trust services.datafordeler.dk only when the OS doesn't trust its cert. if (challenge is ServerTrustAuthenticationChallenge && challenge.host == 'services.datafordeler.dk') { challenge.continueWithCredential( ServerTrustNetworkCredential.forChallenge(challenge), ); return; } // For other challenges (Basic/Digest/NTLM/Client cert), handle as needed // or fail so the error surfaces: challenge.continueAndFail(); } @override Widget build(BuildContext context) { return Scaffold( body: ArcGISMapView( controllerProvider: () => ArcGISMapView.createController() ..arcGISMap = ArcGISMap.withBasemapStyle(BasemapStyle.arcGISTopographic), ), ); } }
If you use a toolkit-based authenticator instead of handling the API directly, the toolkit also includes UI and handling for server‑trust prompts. [developers...arcgis.com]
thanks for the help