我编写了一个Android应用程序,使用DownloadManager将示例PDF文件下载到下载目录。这是代码:
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_vertretungsplan);
Button dlbutton = (Button) findViewById(R.id.buttondownload);
final Context c = this;
dlbutton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
DownloadManager.Request request = new DownloadManager.Request(Uri.parse(myurl));
request.setTitle("Vertretungsplan");
request.setDescription("wird heruntergeladen");
request.allowScanningByMediaScanner();
request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED);
String filename = URLUtil.guessFileName(myurl, null, MimeTypeMap.getFileExtensionFromUrl(myurl));
request.setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS, filename);
DownloadManager manager = (DownloadManager) c.getSystemService(Context.DOWNLOAD_SERVICE);
manager.enqueue(request);
}
});
}
现在,我尝试在我的Xperia Z3 Android 6.0上从Android Studio调试运行它。当我点击下载按钮时,会发生以下错误:
E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.example.markwitt.schul_app, PID: 29297
java.lang.SecurityException: No permission to write to /storage/emulated/0/Download/hrpsampletable.pdf: Neither user 10047 nor current process has android.permission.WRITE_EXTERNAL_STORAGE.
at android.os.Parcel.readException(Parcel.java:1627)
at android.database.DatabaseUtils.readExceptionFromParcel(DatabaseUtils.java:183)
at android.database.DatabaseUtils.readExceptionFromParcel(DatabaseUtils.java:135)
at android.content.ContentProviderProxy.insert(ContentProviderNative.java:476)
at android.content.ContentResolver.insert(ContentResolver.java:1240)
at android.app.DownloadManager.enqueue(DownloadManager.java:946)
at com.example.markwitt.schul_app.Vertretungsplan$1.onClick(Vertretungsplan.java:59)
at android.view.View.performClick(View.java:5280)
at android.view.View$PerformClick.run(View.java:21239)
at android.os.Handler.handleCallback(Handler.java:739)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:224)
at android.app.ActivityThread.main(ActivityThread.java:5526)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:726)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616)
断开与目标VM的连接,地址:'localhost:8600',transport:'socket'
(在第三行)它显示它没有外部存储的写权限。
但我的AndroidManifest设置正确:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.markwitt.schul_app">
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.INTERNET" />
<application
android:launchMode="singleTop"
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".Stundenplan">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:name=".Vertretungsplan"></activity>
</application>
我需要做什么?
您收到此错误的原因是您的应用在Android 6.0(API级别23)中运行。从API级别> = 23,您需要在运行时检查权限。您的代码适用于23级以下。因此,请先检查您的用户是否已授予使用存储空间的权限:
if (checkSelfPermission(android.Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED) {
Log.e("Permission error","You have permission");
return true;
}
如果没有,则提示请求:
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, REQUEST_CODE);
总的来看如下:
public boolean haveStoragePermission() {
if (Build.VERSION.SDK_INT >= 23) {
if (checkSelfPermission(android.Manifest.permission.WRITE_EXTERNAL_STORAGE)
== PackageManager.PERMISSION_GRANTED) {
Log.e("Permission error","You have permission");
return true;
} else {
Log.e("Permission error","You have asked for permission");
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, 1);
return false;
}
}
else { //you dont need to worry about these stuff below api level 23
Log.e("Permission error","You already have the permission");
return true;
}
}
最后一件事:)通过回调接收结果:
@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if(grantResults[0]== PackageManager.PERMISSION_GRANTED){
//you have the permission now.
DownloadManager.Request request = new DownloadManager.Request(Uri.parse(myurl));
request.setTitle("Vertretungsplan");
request.setDescription("wird heruntergeladen");
request.allowScanningByMediaScanner();
request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED);
String filename = URLUtil.guessFileName(myurl, null, MimeTypeMap.getFileExtensionFromUrl(myurl));
request.setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS, filename);
DownloadManager manager = (DownloadManager) c.getSystemService(Context.DOWNLOAD_SERVICE);
manager.enqueue(request);
}
}
或者,您可以使用我的自定义类PermissionCheck
来轻松处理所有这些实现。这是班级:
import android.Manifest;
import android.app.Activity;
import android.content.Context;
import android.content.pm.PackageManager;
import android.support.v4.app.ActivityCompat;
/**
* Created by Tushar on 6/30/2017.
*/
public class PermissionCheck{
public static boolean readAndWriteExternalStorage(Context context){
if(ActivityCompat.checkSelfPermission(context, Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED || ActivityCompat.checkSelfPermission(context, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED){
ActivityCompat.requestPermissions((Activity) context, new String[]{Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.READ_EXTERNAL_STORAGE}, 1);
return false;
}else{
return true;
}
}
public static boolean audioRecord(Context context){
if(ActivityCompat.checkSelfPermission(context, Manifest.permission.RECORD_AUDIO) != PackageManager.PERMISSION_GRANTED ){
ActivityCompat.requestPermissions((Activity) context, new String[]{Manifest.permission.RECORD_AUDIO}, 2);
return false;
}else{
return true;
}
}
public static boolean readAndWriteContacts(Context context){
if(ActivityCompat.checkSelfPermission(context, Manifest.permission.READ_CONTACTS) != PackageManager.PERMISSION_GRANTED || ActivityCompat.checkSelfPermission(context, Manifest.permission.WRITE_CONTACTS) != PackageManager.PERMISSION_GRANTED){
ActivityCompat.requestPermissions((Activity) context, new String[]{Manifest.permission.READ_CONTACTS, Manifest.permission.WRITE_CONTACTS}, 3);
return false;
}else{
return true;
}
}
public static boolean vibrate(Context context){
if(ActivityCompat.checkSelfPermission(context, Manifest.permission.VIBRATE) != PackageManager.PERMISSION_GRANTED){
ActivityCompat.requestPermissions((Activity) context, new String[]{Manifest.permission.VIBRATE}, 4);
return false;
}else{
return true;
}
}
public static boolean sendSms(Context context){
if(ActivityCompat.checkSelfPermission(context, Manifest.permission.SEND_SMS) != PackageManager.PERMISSION_GRANTED){
ActivityCompat.requestPermissions((Activity) context, new String[]{Manifest.permission.SEND_SMS}, 5);
return false;
}else{
return true;
}
}
//Just like this you can implement rest of the permissions.
}
用法:
if(PermissionCheck.readAndWriteExternalStorage(context)){
//Your read write code.
}
if(PermissionCheck.sendSms(context)){
//Your sms sending code.
}
**请注意,这些方法调用将自动请求权限,并且您的onRequestPermissionsResult
也将被触发。 :)
不需要做所有这些。只需将以下代码粘贴到onCreate()
函数上:
private static int REQUEST_CODE=1;
ActivityCompat.requestPermissions(this, new String[]{
Manifest.permission.WRITE_EXTERNAL_STORAGE
}, REQUEST_CODE);
我在运行自定义标签应用程序的API 23模拟器(24和25运行良好)上遇到了同样的问题。我尝试了这个解决方案,以及其他一些变体,我可以看到我被授予了许可,但问题仍然存在于任何下载尝试中。当我在真实设备上运行应用程序(没有权限请求代码)时,系统会自动提示我允许Google访问存储空间 - 而不是我的应用程序。我删除了运行时权限的代码并设置了浏览器的权限(模拟器上的默认值)来访问存储,我的应用程序工作正常。以下帖子提供了一些有关模拟器可能发生的事情的见解:Requesting and allowing WRITE_EXTERNAL_STORAGE permission at runtime has no effects on the current session
确保您的Manifest.xml文件中包含READ_EXTERNAL_STORAGE和WRITE_EXTERNAL_STORAGE权限:
然后在下载功能中包含此代码
if(ActivityCompat.checkSelfPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED || ActivityCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED){
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.WRITE_EXTERNAL_STORAGE}, 1);
// this will request for permission when permission is not true
}else{
// Download code here
}