Android 10 及以上机型存储文件到出错而奔溃

React Native 2020-11-28 阅读 19 评论 0

问题描述

在 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>
最后更新 2020-11-28
MIP.watch('startSearch', function (newVal, oldVal) { if(newVal) { var keyword = MIP.getData('keyword'); console.log(keyword); // 替换当前历史记录,新增 MIP.viewer.open('/s/' + keyword, {replace: true}); setTimeout(function () { MIP.setData({startSearch: false}) }, 1000); } }); MIP.watch('goHome', function (newVal, oldVal) { MIP.viewer.open('/', {replace: false}); });