清除应用存储后OSMDroid示例代码无法加载地图瓦片的求助
问题解决思路
核心问题定位
- Android 13+存储权限适配失效:
WRITE_EXTERNAL_STORAGE权限已废弃,系统不再授予,导致osmdroid无法创建外部缓存目录,触发空指针错误。 - SSL握手失败:MAPNIK瓦片服务器的证书链验证不通过,无法下载瓦片。
- 缓存目录未正确初始化:清除存储后,默认缓存路径丢失,未自动重建。
分步解决方案
1. 适配Android 13+存储权限(推荐使用应用私有存储)
无需申请外部存储权限,直接配置osmdroid使用应用私有目录存储瓦片缓存,彻底规避权限问题:
private lateinit var map: MapView override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) // 初始化osmdroid配置,指定应用私有缓存目录 val config = Configuration.getInstance() val appCacheDir = File(filesDir, "osmdroid_cache") config.setOsmdroidBasePath(appCacheDir) config.setOsmdroidTileCache(File(appCacheDir, "map_tiles")) // 加载配置并设置布局 config.load(this, PreferenceManager.getDefaultSharedPreferences(this)) setContentView(R.layout.main) map = findViewById(R.id.map) map.setTileSource(TileSourceFactory.MAPNIK) }
同时移除Manifest中已废弃的WRITE_EXTERNAL_STORAGE、READ_EXTERNAL_STORAGE权限,以及android:requestLegacyExternalStorage="true"配置。
2. 修复SSL握手失败问题
MAPNIK瓦片服务器使用Let's Encrypt证书,部分设备因根证书缺失导致验证失败,可选择以下方案:
- 方案一:更换兼容瓦片源
改用证书验证无问题的瓦片源,例如:map.setTileSource(TileSourceFactory.OpenTopo) - 方案二:临时跳过SSL验证(仅测试用)
创建信任所有证书的SSL配置注入osmdroid下载器(不推荐生产环境使用):// 提前在初始化前配置 fun createUnsafeSSLContext(): SSLContext { val trustAllCerts = arrayOf<TrustManager>(object : X509TrustManager { override fun checkClientTrusted(chain: Array<out X509Certificate>?, authType: String?) {} override fun checkServerTrusted(chain: Array<out X509Certificate>?, authType: String?) {} override fun getAcceptedIssuers(): Array<X509Certificate> = emptyArray() }) val sslContext = SSLContext.getInstance("SSL") sslContext.init(null, trustAllCerts, SecureRandom()) return sslContext } // 在onCreate中地图初始化前调用 val sslContext = createUnsafeSSLContext() OkHttpClientFactory.setOkHttpClient( OkHttpClient.Builder() .sslSocketFactory(sslContext.socketFactory, sslContext.trustManager as X509TrustManager) .hostnameVerifier { _, _ -> true } .build() )
3. 确保缓存目录可写
添加代码主动创建并验证缓存目录,避免空指针:
val appCacheDir = File(filesDir, "osmdroid_cache") if (!appCacheDir.exists()) { appCacheDir.mkdirs() } val tileCacheDir = File(appCacheDir, "map_tiles") if (!tileCacheDir.exists()) { tileCacheDir.mkdirs() } // 验证可写性 if (StorageUtils.isWritable(tileCacheDir)) { Log.d("Osmdroid", "缓存目录可写") } else { Log.e("Osmdroid", "缓存目录不可写") }
内容的提问来源于stack exchange,提问作者Malachi Holden
相关产品推荐
相关产品推荐

