Android 10 及以上机型存储文件到出错而奔溃
问题描述
在 React Native,使用以下代码,实现下载 apk 并安装升级。
import RNFetchBlob from 'rn-fetch-blob';
let downloadPath = RNFetchBlob.fs.dirs.DownloadDir + "/test.apk";
let config = {
addAndroidDownloads : {
useDownloadManager : true,
title : "test.apk",
description : '下载完成后,将自动安装更新包',
mime : 'application/vnd.android.package-archive',
mediaScannable : true,
notification : true,
path: downloadPath,
}
}
RNFetchBlob.config(config).fetch('GET', "http://localhost/test.apk").then((resp) => {
RNFetchBlob.android.actionViewIntent(downloadPath, 'application/vnd.android.package-archive')
});
在 android 10 以下的机型一直没有问题。但是在 android 10 以上会报错而奔溃,如下:
18516-18761/com.example E/AndroidRuntime: FATAL EXCEPTION: OkHttp Dispatcher
Process: com.example, PID: 18516
java.lang.ClassCastException: okhttp3.internal.http.RealResponseBody cannot be cast to com.RNFetchBlob.Response.RNFetchBlobFileResp
at com.RNFetchBlob.RNFetchBlobReq.done(RNFetchBlobReq.java:594)
at com.RNFetchBlob.RNFetchBlobReq.access$100(RNFetchBlobReq.java:72)
at com.RNFetchBlob.RNFetchBlobReq$3.onResponse(RNFetchBlobReq.java:493)
at okhttp3.RealCall$AsyncCall.execute(RealCall.java:206)
at okhttp3.internal.NamedRunnable.run(NamedRunnable.java:32)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
at java.lang.Thread.run(Thread.java:919)
解决方法
参考官方文档 Android 存储用例和最佳做法,Android 10 针对应用推出了一种新的存储范例,称为分区存储,分区存储改变了应用在设备的外部存储设备中存储和访问文件的方式。为了兼容 Android 10 以下的机型,在 AndroidManifest.xml
中增加 android:requestLegacyExternalStorage="true"
。
<manifest ... >
<application android:requestLegacyExternalStorage="true" ... >
...
</application>
</manifest>