首页 > 解决方案 > 使用 DownloadManager 下载 HTTP 资源在 android9 上不起作用

问题描述

我有一个在原生 android9 上运行的 react-native 应用程序,现在我想使用 DownloadManager 下载文件,它是一个http资源。开始下载时,没有立即显示通知,也没有下载进度,等了几分钟就显示下载失败。DownloadManager.COLUMN_REASON是 1004,根据文档,它意味着 ERROR_HTTP_DATA_ERROR。我在AndroidManifest.xml中设置了 networkSecurityConfig。如果我将文件更改为https资源,它可以正常工作,但仍然存在一个问题,即在下载完成之前它也不会在通知栏中显示下载进度。我已将NotificationVisibility设置为VISIBILITY_VISIBLE_NOTIFY_COMPLETED。正常的 http 请求,例如 get、post 效果很好。AndroidManifest.xml

...
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/> 
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES"/>

<application
  android:name=".MainApplication"
  android:label="@string/app_name"
  android:icon="@mipmap/ic_launcher"
  android:roundIcon="@mipmap/ic_launcher_round"
  android:allowBackup="false"
  android:networkSecurityConfig="@xml/network_security_config"
  android:theme="@style/AppTheme">
  <uses-library
    android:name="org.apache.http.legacy"
    android:required="false" />
  <activity
    android:name=".MainActivity"
    ...>
    <intent-filter>
        <action android:name="android.intent.action.MAIN" />
        <category android:name="android.intent.category.LAUNCHER" />
    </intent-filter>
  </activity>
  <provider
      android:name="androidx.core.content.FileProvider"
      android:authorities="${applicationId}.fileprovider"
      android:grantUriPermissions="true"
      android:exported="false">
      <meta-data
          android:name="android.support.FILE_PROVIDER_PATHS"
          android:resource="@xml/file_paths" />
  </provider>
  <receiver android:name="com.cityvoice.cubebrain.MyBroadcastReceiver">
    <intent-filter>
        <action android:name="android.intent.action.DOWNLOAD_COMPLETE"/>
    </intent-filter>
  </receiver>
</application>

... file_paths.xml

<?xml version="1.0" encoding="utf-8"?>
<resources>
  <paths>
    <external-files-path path="" name="Download" />
    </paths>
</resources>

network_security_config.xml

<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
    <base-config cleartextTrafficPermitted="true"/>
</network-security-config>

AndroidDownloadManager.java

public class AndroidDownloadManager {
    ...

    public AndroidDownloadManager(Context context, String url, String name) {
        this.context = context;
        this.url = url;
        this.name = name;
    }

    public AndroidDownloadManager setListener(AndroidDownloadManagerListener listener) {
        this.listener = listener;
        return this;
    }

    public void download() {
        DownloadManager.Request request = new DownloadManager.Request(Uri.parse(url));
        request.setAllowedOverRoaming(false);
        request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED);
        request.setTitle(name);
        request.setDescription("downloading......");
        request.setVisibleInDownloadsUi(true);
        File file = new File(context.getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS), name);
        request.setDestinationUri(Uri.fromFile(file));
        path = file.getAbsolutePath();
        if (downloadManager == null) {
            downloadManager = (DownloadManager) context.getSystemService(Context.DOWNLOAD_SERVICE);
        }
        if (downloadManager != null) {
            if (listener != null) {
                listener.onPrepare();
            }
            downloadId = downloadManager.enqueue(request);
        }
        context.registerReceiver(receiver, new IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE));
    }

    private MyBroadcastReceiver receiver = new MyBroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            DownloadManager.Query query = new DownloadManager.Query();
            Log.d(TAG, "onReceive >>>>" + url);
            query.setFilterById(downloadId);
            Cursor cursor = downloadManager.query(query);
            if (cursor.moveToFirst()) {
                int status = cursor.getInt(cursor.getColumnIndex(DownloadManager.COLUMN_STATUS));
                switch (status) {
                    case DownloadManager.STATUS_PAUSED:
                        break;
                    case DownloadManager.STATUS_PENDING:
                        break;
                    case DownloadManager.STATUS_RUNNING:
                        break;
                    case DownloadManager.STATUS_SUCCESSFUL:
                        if (listener != null) {
                            listener.onSuccess(path);
                        }
                        cursor.close();
                        context.unregisterReceiver(receiver);
                        break;
                    case DownloadManager.STATUS_FAILED:
                        if (listener != null) {
                            listener.onFailed(new Exception("failed"));
                        }
                        cursor.close();
                        context.unregisterReceiver(receiver);
                        break;
                }
            }
        }
    };
}

标签: androidreact-native

解决方案


推荐阅读