You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

Android 10与Android 11系统下设置外部存储或自定义地图下载路径的方法(Flutter环境)

Setting Custom Storage Path for Map Downloads on Android 10 & 11 (Flutter)

Hey there, let's break down how to properly configure a custom external or internal storage path for map downloads in your Flutter project, specifically targeting Android 10 (API 29) and Android 11 (API 30). The key here is adapting to Android's Scoped Storage system introduced in Android 10, which changes how apps access external storage.

First: Understand Scoped Storage Implications

Android 10+ restricts direct access to most external storage locations to protect user privacy. There are two main paths you can use, each with different permission requirements:

  • App-specific external storage: This is a private directory for your app (e.g., Android/data/com.your.app/files/). No extra permissions needed, and data is deleted when your app is uninstalled. This is the recommended approach.
  • Public storage directories: Like the Downloads or Documents folder. Requires the MANAGE_EXTERNAL_STORAGE permission on Android 11+, and users have to manually grant access via system settings. Only use this if users need direct access to map files outside your app.

Step 1: Add Required Dependencies

To handle storage paths and permissions in Flutter, add these packages to your pubspec.yaml:

dependencies:
  flutter:
    sdk: flutter
  path_provider: ^2.0.15  # For accessing storage directories
  permission_handler: ^10.2.0  # For requesting permissions

Step 2: Get a Valid Storage Path

This path requires no extra permissions and is compliant with Android 10+ rules:

import 'dart:io';
import 'package:path_provider/path_provider.dart';

Future<String> getAppSpecificMapPath() async {
  // Get the app's private external storage directory
  Directory? externalDir = await getExternalStorageDirectory();
  if (externalDir == null) throw Exception("Failed to access external storage");

  // Create a subdirectory for map files (ensure it exists)
  final mapDir = Directory('${externalDir.path}/MapCache');
  await mapDir.create(recursive: true);
  
  return mapDir.path;
}

Option 2: Public Storage Directory (Android 11+)

If you need to use a public folder like Downloads, you'll need to request the MANAGE_EXTERNAL_STORAGE permission:

import 'dart:io';
import 'package:path_provider/path_provider.dart';
import 'package:permission_handler/permission_handler.dart';

Future<String> getPublicMapPath() async {
  // Check and request MANAGE_EXTERNAL_STORAGE permission
  var permissionStatus = await Permission.manageExternalStorage.status;
  if (!permissionStatus.isGranted) {
    permissionStatus = await Permission.manageExternalStorage.request();
    if (!permissionStatus.isGranted) {
      // If permission is denied, redirect user to app settings
      await openAppSettings();
      throw Exception("Storage permission is required to use this path");
    }
  }

  // Get the public Downloads directory
  Directory? publicDir = await getExternalStoragePublicDirectory(StorageDirectory.downloads);
  if (publicDir == null) throw Exception("Failed to access public storage");

  // Create a subdirectory for maps
  final mapDir = Directory('${publicDir.path}/MyCustomMaps');
  await mapDir.create(recursive: true);
  
  return mapDir.path;
}

Step 3: Configure Your SDKOptions Correctly

Once you have a valid path, pass it to your SDKOptions initialization. Make sure the directory exists before initializing the SDK (the code above handles this with create(recursive: true)):

void initMapSDK() async {
  try {
    // Choose either the app-specific or public path
    String externalPath = await getAppSpecificMapPath();
    // String externalPath = await getPublicMapPath();

    SDKOptions sdkOptions = SDKOptions.withAccessKeySecretAndCachePathCacheSizeAndPersistentMapPath(
      sKey, 
      sSecret, 
      externalPath, 
      ConfigurationSingleton.instance.cacheSizeBytes, 
      externalPath
    );

    // Initialize your map SDK with these options
    // ... (SDK initialization code here)
  } catch (e) {
    print("Map SDK initialization failed: $e");
  }
}

Step 4: Update AndroidManifest.xml

  • For app-specific storage: No extra permissions needed, but you can add this for backward compatibility with Android 9 and below:
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" android:maxSdkVersion="28" />
    
  • For public storage: Add the MANAGE_EXTERNAL_STORAGE permission for Android 11+:
    <uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" android:minSdkVersion="30" />
    

Important Notes

  • Avoid using android:requestLegacyExternalStorage="true" in your AndroidManifest.xml (a workaround for Android 10). This is deprecated in Android 12+ and won't be supported long-term.
  • Always test on real Android 10/11 devices—emulators may have different storage behavior.
  • Ensure your map SDK is updated to the latest version, as older SDKs may not fully support Scoped Storage.

内容的提问来源于stack exchange,提问作者Benjamin Hernández

火山引擎 最新活动