将请求排队到 DownloadManager 时应用程序崩溃

App crashes when enqueuing request to DownloadManager

我正在尝试制作一个使用 DownloadManager 下载 iCal 文件的应用程序。经过一些研究,我找不到解决我的问题的方法。使用 Android Studio 调试器,我发现应用程序在接收请求时崩溃。这是我在 Android 监视器中遇到的错误:

 java.lang.SecurityException: Permission Denial: writing com.android.providers.downloads.DownloadProvider uri content://downloads/my_downloads from pid=5082, uid=10208 requires android.permission.INTERNET, or grantUriPermission()

我不明白为什么它需要已经给出的 android.permission.INTERNET,如下面的 AndroidManifest 所示:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="galisson.esiea.pst3.smartwatch">

<application
    android:allowBackup="true"
    android:icon="@drawable/smartwatch"
    android:label="@string/app_name"
    android:roundIcon="@mipmap/ic_launcher_round"
    android:supportsRtl="true"
    android:theme="@style/AppTheme">
    <activity android:name=".MainActivity">
        <intent-filter>
            <action android:name="android.intent.action.MAIN" />

            <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>
    </activity>

    <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.READ_EXTERNAL_STORAGE" />


</application>

这是我的 MainActivity :

public class MainActivity extends AppCompatActivity {

     EditText url;
     Button buttonAdd;

     @Override
     protected void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
         setContentView(R.layout.activity_main);

         url = (EditText) findViewById(R.id.editTextLink);
         buttonAdd = (Button) findViewById(R.id.buttonADD);

         buttonAdd.setOnClickListener(new View.OnClickListener() {
             @Override
             public void onClick(View v) {
                 if(!url.getText().toString().isEmpty()) {
                     Uri iCalURI = Uri.parse(url.getText().toString());

                     DownloadData(iCalURI);

                 }
             }
         });


     }

     private void DownloadData(Uri p_uri) {

         DownloadManager manager = (DownloadManager) getSystemService(Context.DOWNLOAD_SERVICE);
         DownloadManager.Request request = new DownloadManager.Request(p_uri);

         request.setDescription("iCal Calendar downloading");
         request.setTitle("iCal calendar");
         request.setAllowedNetworkTypes(DownloadManager.Request.NETWORK_WIFI | DownloadManager.Request.NETWORK_MOBILE);                      //Restrict the types of networks over which this download may proceed.
         request.setAllowedOverRoaming(false);                                                                                               //Set whether this download may proceed over a roaming connection.
         request.allowScanningByMediaScanner();
         request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED);
         request.setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS, "iCal_tmp.ics");

         manager.enqueue(request);           //this is where it crashes

         return;
     }
  }

我的问题是权限本身还是请求本身?

首先授予您需要的权限。

public boolean isStoragePermissionGranted() {
    if (Build.VERSION.SDK_INT >= 23) {
        if (checkSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE)
                == PackageManager.PERMISSION_GRANTED) {
            Log.v(TAG, "Permission is granted");

            writeFilesToSdCard();
            return true;
        } else {

            Log.v(TAG, "Permission is revoked");
            ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, 1);
            return false;
        }
    } else { //permission is automatically granted on sdk<23 upon installation
        writeFilesToSdCard();
        return true;
    }
}

然后用覆盖的方法请求它。

@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
    super.onRequestPermissionsResult(requestCode, permissions, grantResults);
    if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
        Log.v(TAG, "Permission: " + permissions[0] + "was " + grantResults[0]);
        //resume tasks needing this permission
    }
}

注意:不要忘记将权限放在 <application> 标签之外的清单中。

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.myproject">

    <uses-permission android:name="android.permission.INTERNET" />    
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

    <application
        //
    </application>

</manifest>