在Lollipop中,下载功能在我的应用程序中运行良好,但当我升级到Marshmallow时,我的应用程序崩溃并在我尝试从互联网下载到SD卡时出现此错误:
Neither user nor current process has android.permission.WRITE_EXTERNAL_STORAGE
它抱怨这行代码:
DownloadManager manager = (DownloadManager) getSystemService(Context.DOWNLOAD_SERVICE);
manager.enqueue(request);
我在应用程序外的清单中拥有权限:
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
我清理并重建了项目,但它仍然崩溃。
答案 0 :(得分:315)
您应该使用以下方法检查用户是否已授予外部存储权限:
if (checkSelfPermission(android.Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED) {
Log.v(TAG,"Permission is granted");
//File write logic here
return true;
}
如果没有,您需要让用户授予您的应用权限:
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, REQUEST_CODE);
当然这些仅适用于棉花糖设备,因此您需要检查您的应用是否在Marshmallow上运行:
if (Build.VERSION.SDK_INT >= 23) {
//do your check here
}
还要确保您的活动实施OnRequestPermissionResult
整个权限如下:
public boolean isStoragePermissionGranted() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
if (checkSelfPermission(android.Manifest.permission.WRITE_EXTERNAL_STORAGE)
== PackageManager.PERMISSION_GRANTED) {
Log.v(TAG,"Permission is granted");
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
Log.v(TAG,"Permission is granted");
return true;
}
}
权限结果回调:
@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if(grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED){
Log.v(TAG,"Permission: "+permissions[0]+ "was "+grantResults[0]);
//resume tasks needing this permission
}
}
答案 1 :(得分:31)
Android的权限系统是最大的安全问题之一 因为在安装时要求这些权限。一旦 安装后,应用程序将能够访问所有内容 没有任何用户的确认授予什么确切的应用程序 得到了许可。
Android 6.0 Marshmallow引入了最大的变化之一 权限模型添加了运行时权限,一个新的 用于替换现有安装时权限的权限模型 模拟目标API 23并且应用程序在Android 6.0+上运行时 设备
礼貌用于 Requesting Permissions at Run Time 。
示例
将此声明为全局
private static final int PERMISSION_REQUEST_CODE = 1;
在 onCreate()
部分
setContentView(R.layout.your_xml);
if (Build.VERSION.SDK_INT >= 23)
{
if (checkPermission())
{
// Code for above or equal 23 API Oriented Device
// Your Permission granted already .Do next code
} else {
requestPermission(); // Code for permission
}
}
else
{
// Code for Below 23 API Oriented Device
// Do next code
}
现在添加 checkPermission()和 requestPermission()
private boolean checkPermission() {
int result = ContextCompat.checkSelfPermission(Your_Activity.this, android.Manifest.permission.WRITE_EXTERNAL_STORAGE);
if (result == PackageManager.PERMISSION_GRANTED) {
return true;
} else {
return false;
}
}
private void requestPermission() {
if (ActivityCompat.shouldShowRequestPermissionRationale(Your_Activity.this, android.Manifest.permission.WRITE_EXTERNAL_STORAGE)) {
Toast.makeText(Your_Activity.this, "Write External Storage permission allows us to do store images. Please allow this permission in App Settings.", Toast.LENGTH_LONG).show();
} else {
ActivityCompat.requestPermissions(Your_Activity.this, new String[]{android.Manifest.permission.WRITE_EXTERNAL_STORAGE}, PERMISSION_REQUEST_CODE);
}
}
@Override
public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) {
switch (requestCode) {
case PERMISSION_REQUEST_CODE:
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
Log.e("value", "Permission Granted, Now you can use local drive .");
} else {
Log.e("value", "Permission Denied, You cannot use local drive .");
}
break;
}
}
<强> onRequestPermissionsResult 强>
此界面是接收结果的合同 许可请求。
答案 2 :(得分:20)
除非明确要求在外部存储上书写,否则您始终可以选择将文件保存在app目录中。在我的情况下,我不得不保存文件,浪费了2至3天后,我发现我是否更改了存储路径
Environment.getExternalStorageDirectory()
到
getApplicationContext().getFilesDir().getPath() //which returns the internal app files directory path
它在所有设备上都像魅力一样。 这是因为要在外部存储上写入,您需要额外的权限,但在内部应用程序目录中编写很简单。
答案 3 :(得分:19)
检查API级别23中的多个权限 第1步:
String[] permissions = new String[]{
Manifest.permission.INTERNET,
Manifest.permission.READ_PHONE_STATE,
Manifest.permission.READ_EXTERNAL_STORAGE,
Manifest.permission.WRITE_EXTERNAL_STORAGE,
Manifest.permission.VIBRATE,
Manifest.permission.RECORD_AUDIO,
};
第2步:
private boolean checkPermissions() {
int result;
List<String> listPermissionsNeeded = new ArrayList<>();
for (String p : permissions) {
result = ContextCompat.checkSelfPermission(this, p);
if (result != PackageManager.PERMISSION_GRANTED) {
listPermissionsNeeded.add(p);
}
}
if (!listPermissionsNeeded.isEmpty()) {
ActivityCompat.requestPermissions(this, listPermissionsNeeded.toArray(new String[listPermissionsNeeded.size()]), 100);
return false;
}
return true;
}
第3步:
@Override
public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) {
if (requestCode == 100) {
if (grantResults.length > 0
&& grantResults[0] == PackageManager.PERMISSION_GRANTED) {
// do something
}
return;
}
}
第4步: 在onCreate of Activity中 checkPermissions();
答案 4 :(得分:5)
您需要在marshmallow中使用运行时权限 https://developer.android.com/training/permissions/requesting.html
您可以查看应用信息 - &gt;许可
您的应用是否获得写入外部存储的权限
答案 5 :(得分:4)
似乎用户拒绝了权限,应用尝试写入外部磁盘,从而导致错误。
@Override
public void onRequestPermissionsResult(int requestCode,
String permissions[], int[] grantResults) {
switch (requestCode) {
case MY_PERMISSIONS_REQUEST_READ_CONTACTS: {
// If request is cancelled, the result arrays are empty.
if (grantResults.length > 0
&& grantResults[0] == PackageManager.PERMISSION_GRANTED) {
// permission was granted, yay! Do the
// contacts-related task you need to do.
} else {
// permission denied, boo! Disable the
// functionality that depends on this permission.
}
return;
}
// other 'case' lines to check for other
// permissions this app might request
}
}
检查https://developer.android.com/training/permissions/requesting.html
此视频可让您更好地了解用户体验,处理运行时权限https://www.youtube.com/watch?v=iZqDdvhTZj0
答案 6 :(得分:0)
经过大量搜索后,这段代码对我有用:
检查已有的权限: 检查WRITE_EXTERNAL_STORAGE权限是否允许?
if(isReadStorageAllowed()){
//If permission is already having then showing the toast
//Toast.makeText(SplashActivity.this,"You already have the permission",Toast.LENGTH_LONG).show();
//Existing the method with return
return;
}else{
requestStoragePermission();
}
private boolean isReadStorageAllowed() {
//Getting the permission status
int result = ContextCompat.checkSelfPermission(this, android.Manifest.permission.WRITE_EXTERNAL_STORAGE);
//If permission is granted returning true
if (result == PackageManager.PERMISSION_GRANTED)
return true;
//If permission is not granted returning false
return false;
}
//Requesting permission
private void requestStoragePermission(){
if (ActivityCompat.shouldShowRequestPermissionRationale(this, android.Manifest.permission.WRITE_EXTERNAL_STORAGE)){
//If the user has denied the permission previously your code will come to this block
//Here you can explain why you need this permission
//Explain here why you need this permission
}
//And finally ask for the permission
ActivityCompat.requestPermissions(this,new String[]{android.Manifest.permission.WRITE_EXTERNAL_STORAGE},REQUEST_WRITE_STORAGE);
}
实现覆盖onRequestPermissionsResult方法进行检查是用户允许还是拒绝
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
//Checking the request code of our request
if(requestCode == REQUEST_WRITE_STORAGE){
//If permission is granted
if(grantResults.length >0 && grantResults[0] == PackageManager.PERMISSION_GRANTED){
//Displaying a toast
Toast.makeText(this,"Permission granted now you can read the storage",Toast.LENGTH_LONG).show();
}else{
//Displaying another toast if permission is not granted
Toast.makeText(this,"Oops you just denied the permission",Toast.LENGTH_LONG).show();
}
}
答案 7 :(得分:0)
它对我有用
boolean hasPermission = (ContextCompat.checkSelfPermission(AddContactActivity.this,
Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED);
if (!hasPermission) {
ActivityCompat.requestPermissions(AddContactActivity.this,
new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE},
REQUEST_WRITE_STORAGE);
}
@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
switch (requestCode)
{
case REQUEST_WRITE_STORAGE: {
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED)
{
//reload my activity with permission granted or use the features what required the permission
} else
{
Toast.makeText(AddContactActivity.this, "The app was not allowed to write to your storage. Hence, it cannot function properly. Please consider granting it this permission", Toast.LENGTH_LONG).show();
}
}
}
}
答案 8 :(得分:0)
从marshmallow版本开发人员需要向用户请求运行时权限。 让我给你整个过程来询问运行时权限。
我在这里使用引用:marshmallow runtime permissions android。
首先创建一个检查是否给出所有权限的方法
private boolean checkAndRequestPermissions() {
int camerapermission = ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA);
int writepermission = ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE);
int permissionLocation = ContextCompat.checkSelfPermission(this,Manifest.permission.ACCESS_FINE_LOCATION);
int permissionRecordAudio = ContextCompat.checkSelfPermission(this, Manifest.permission.RECORD_AUDIO);
List<String> listPermissionsNeeded = new ArrayList<>();
if (camerapermission != PackageManager.PERMISSION_GRANTED) {
listPermissionsNeeded.add(Manifest.permission.CAMERA);
}
if (writepermission != PackageManager.PERMISSION_GRANTED) {
listPermissionsNeeded.add(Manifest.permission.WRITE_EXTERNAL_STORAGE);
}
if (permissionLocation != PackageManager.PERMISSION_GRANTED) {
listPermissionsNeeded.add(Manifest.permission.ACCESS_FINE_LOCATION);
}
if (permissionRecordAudio != PackageManager.PERMISSION_GRANTED) {
listPermissionsNeeded.add(Manifest.permission.RECORD_AUDIO);
}
if (!listPermissionsNeeded.isEmpty()) {
ActivityCompat.requestPermissions(this, listPermissionsNeeded.toArray(new String[listPermissionsNeeded.size()]), REQUEST_ID_MULTIPLE_PERMISSIONS);
return false;
}
return true;
}
现在这是在上述方法之后运行的代码。我们将覆盖onRequestPermissionsResult()
方法:
@Override
public void onRequestPermissionsResult(int requestCode,
String permissions[], int[] grantResults) {
Log.d(TAG, "Permission callback called-------");
switch (requestCode) {
case REQUEST_ID_MULTIPLE_PERMISSIONS: {
Map<String, Integer> perms = new HashMap<>();
// Initialize the map with both permissions
perms.put(Manifest.permission.CAMERA, PackageManager.PERMISSION_GRANTED);
perms.put(Manifest.permission.WRITE_EXTERNAL_STORAGE, PackageManager.PERMISSION_GRANTED);
perms.put(Manifest.permission.ACCESS_FINE_LOCATION, PackageManager.PERMISSION_GRANTED);
perms.put(Manifest.permission.RECORD_AUDIO, PackageManager.PERMISSION_GRANTED);
// Fill with actual results from user
if (grantResults.length > 0) {
for (int i = 0; i < permissions.length; i++)
perms.put(permissions[i], grantResults[i]);
// Check for both permissions
if (perms.get(Manifest.permission.CAMERA) == PackageManager.PERMISSION_GRANTED
&& perms.get(Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED
&& perms.get(Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED
&& perms.get(Manifest.permission.RECORD_AUDIO) == PackageManager.PERMISSION_GRANTED) {
Log.d(TAG, "sms & location services permission granted");
// process the normal flow
Intent i = new Intent(MainActivity.this, WelcomeActivity.class);
startActivity(i);
finish();
//else any one or both the permissions are not granted
} else {
Log.d(TAG, "Some permissions are not granted ask again ");
//permission is denied (this is the first time, when "never ask again" is not checked) so ask again explaining the usage of permission
// // shouldShowRequestPermissionRationale will return true
//show the dialog or snackbar saying its necessary and try again otherwise proceed with setup.
if (ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.CAMERA)
|| ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.WRITE_EXTERNAL_STORAGE)
|| ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.ACCESS_FINE_LOCATION)
|| ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.RECORD_AUDIO)) {
showDialogOK("Service Permissions are required for this app",
new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
switch (which) {
case DialogInterface.BUTTON_POSITIVE:
checkAndRequestPermissions();
break;
case DialogInterface.BUTTON_NEGATIVE:
// proceed with logic by disabling the related features or quit the app.
finish();
break;
}
}
});
}
//permission is denied (and never ask again is checked)
//shouldShowRequestPermissionRationale will return false
else {
explain("You need to give some mandatory permissions to continue. Do you want to go to app settings?");
// //proceed with logic by disabling the related features or quit the app.
}
}
}
}
}
}
如果用户点击拒绝选项,则showDialogOK()
方法将用于显示对话框
如果用户点击拒绝,并且点击一个复选框说&#34;再也不会再问'&#34; ,那么explain()
方法将用于显示对话框。
显示对话框的方法:
private void showDialogOK(String message, DialogInterface.OnClickListener okListener) {
new AlertDialog.Builder(this)
.setMessage(message)
.setPositiveButton("OK", okListener)
.setNegativeButton("Cancel", okListener)
.create()
.show();
}
private void explain(String msg){
final android.support.v7.app.AlertDialog.Builder dialog = new android.support.v7.app.AlertDialog.Builder(this);
dialog.setMessage(msg)
.setPositiveButton("Yes", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface paramDialogInterface, int paramInt) {
// permissionsclass.requestPermission(type,code);
startActivity(new Intent(android.provider.Settings.ACTION_APPLICATION_DETAILS_SETTINGS, Uri.parse("package:com.exampledemo.parsaniahardik.marshmallowpermission")));
}
})
.setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface paramDialogInterface, int paramInt) {
finish();
}
});
dialog.show();
}
上面的代码段一次要求四个权限。您还可以根据自己的要求在任何活动中要求任意数量的权限。
答案 9 :(得分:0)
Try this
int permission = ContextCompat.checkSelfPermission(MainActivity.this,
android.Manifest.permission.WRITE_EXTERNAL_STORAGE);
if (permission != PackageManager.PERMISSION_GRANTED) {
Log.i("grant", "Permission to record denied");
if (ActivityCompat.shouldShowRequestPermissionRationale(this,
android.Manifest.permission.WRITE_EXTERNAL_STORAGE)) {
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setMessage(getString(R.string.permsg))
.setTitle(getString(R.string.permtitle));
builder.setPositiveButton(getString(R.string.ok), new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
Log.i("grant", "Clicked");
makeRequest();
}
});
AlertDialog dialog = builder.create();
dialog.show();
} else {
//makeRequest1();
makeRequest();
}
}
protected void makeRequest() {
ActivityCompat.requestPermissions(this,
new String[]{android.Manifest.permission.WRITE_EXTERNAL_STORAGE},
500);
}
@Override
public void onRequestPermissionsResult(int requestCode,
String permissions[], int[] grantResults) {
switch (requestCode) {
case 500: {
if (grantResults.length == 0
|| grantResults[0] !=
PackageManager.PERMISSION_GRANTED) {
Log.i("1", "Permission has been denied by user");
} else {
Log.i("1", "Permission has been granted by user");
}
return;
}
}
}
答案 10 :(得分:0)
在开始下载之前,请检查您的运行时权限,如果您没有此请求的请求权限,则为
requestStoragePermission()
private void requestStoragePermission(){
if (ActivityCompat.shouldShowRequestPermissionRationale(this,
android.Manifest.permission.READ_EXTERNAL_STORAGE))
{
}
ActivityCompat.requestPermissions(this,
new String[]{Manifest.permission.READ_EXTERNAL_STORAGE},
STORAGE_PERMISSION_CODE);
}
@Override
public void onRequestPermissionsResult(int requestCode,
@NonNull String[] permissions,
@NonNull int[] grantResults) {
if(requestCode == STORAGE_PERMISSION_CODE){
if(grantResults.length >0 && grantResults[0] == PackageManager.PERMISSION_GRANTED){
}
else{
Toast.makeText(this,
"Oops you just denied the permission",
Toast.LENGTH_LONG).show();
}
}
}
答案 11 :(得分:0)
可以使用manifest.xml文件以简单的方式授予许可,但是直到api级别23 sdk版本6都可以,从这里开始,如果要获得许可,我们必须要求使用允许所需的权限。
只需在mainActivity.java中添加此代码
Override
public void onClick(View view) {
// Request the permission
ActivityCompat.requestPermissions(MainActivity.this,
new String[]{Manifest.permission.CAMERA},
PERMISSION_REQUEST_CAMERA);
如果需要,请替换CAMERA或添加WRITE_EXTERNAL_STORAGE,并添加唯一代码。
new String[]{Manifest.permission.CAMERA,
Manifest.permission.WRITE_EXTERNAL_STORAGE},
101);
这是获得许可的简单代码。
答案 12 :(得分:0)
我发现的最简单的方法是
private boolean checkPermissions(){
if(ActivityCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED) {
return true;
}
else {
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, PERMISSION_CODE);
return false;
}
}
答案 13 :(得分:0)
将以下代码添加到MainAcitivity中的OnCreate()函数中,该弹出窗口将显示弹出窗口以请求许可:
if (ActivityCompat.shouldShowRequestPermissionRationale(TestActivity.this,
Manifest.permission.WRITE_EXTERNAL_STORAGE)){
}
else {
ActivityCompat.requestPermissions(TestActivity.this,
new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE},
100);
}
答案 14 :(得分:0)
if (ActivityCompat.shouldShowRequestPermissionRationale(getActivity(),
Manifest.permission.WRITE_EXTERNAL_STORAGE)) {
Log.d(TAG, "Permission granted");
} else {
ActivityCompat.requestPermissions(getActivity(),
new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE},
100);
}
fab.setOnClickListener(v -> {
Bitmap b = BitmapFactory.decodeResource(getResources(), R.drawable.refer_pic);
Intent share = new Intent(Intent.ACTION_SEND);
share.setType("image/*");
ByteArrayOutputStream bytes = new ByteArrayOutputStream();
b.compress(Bitmap.CompressFormat.JPEG, 100, bytes);
String path = MediaStore.Images.Media.insertImage(requireActivity().getContentResolver(),
b, "Title", null);
Uri imageUri = Uri.parse(path);
share.putExtra(Intent.EXTRA_STREAM, imageUri);
share.putExtra(Intent.EXTRA_TEXT, "Here is text");
startActivity(Intent.createChooser(share, "Share via"));
});