J'ai programmé une application Android qui télécharge un exemple PDF dans le répertoire de téléchargement à l'aide de DownloadManager. Voici le code:
@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);
}
});
}
Maintenant, j'ai essayé de le déboguer et de l'exécuter à partir de Android Studio sur mon Xperia Z3 Android 6.0. Lorsque j'ai cliqué sur le bouton de téléchargement, cette erreur se produit:
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)
Déconnecté de la machine virtuelle cible, adresse: 'localhost: 8600', transport: 'socket'
(sur la troisième ligne), il m'indique qu'il n'a aucune autorisation d'écriture sur le stockage externe.
Mais mon AndroidManifest est correctement configuré:
<?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>
Qu'est-ce que je dois faire?
Vous obtenez cette erreur car votre application s'exécute dans Android 6.0 (API niveau 23). À partir du niveau API> = 23, vous devrez vérifier l'autorisation en cours d'exécution. Votre code est juste très bien pour un niveau inférieur à 23. Donc, veuillez d'abord vérifier si votre utilisateur a donné l'autorisation d'utiliser le stockage:
if (checkSelfPermission(Android.Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED) {
Log.e("Permission error","You have permission");
return true;
}
Sinon, invitez la demande:
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, REQUEST_CODE);
Le total des choses ressemble à ceci:
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;
}
}
Et dernière chose :) recevoir le résultat par rappel:
@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);
}
}
Ou, vous pouvez simplement utiliser ma classe personnalisée PermissionCheck
pour gérer toute cette implémentation très facilement. Voici la classe:
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.
}
usage:
if(PermissionCheck.readAndWriteExternalStorage(context)){
//Your read write code.
}
if(PermissionCheck.sendSms(context)){
//Your sms sending code.
}
** Notez que, ces méthodes appellent automatiquement les autorisations et que votre onRequestPermissionsResult
sera déclenché. :)
Pas besoin de faire tout ça. Collez simplement le code ci-dessous sur votre fonction onCreate()
:
private static int REQUEST_CODE=1;
ActivityCompat.requestPermissions(this, new String[]{
Manifest.permission.WRITE_EXTERNAL_STORAGE
}, REQUEST_CODE);
Assurez-vous que les autorisations READ_EXTERNAL_STORAGE et WRITE_EXTERNAL_STORAGE se trouvent dans votre fichier Manifest.xml:
Et puis incluez ce code dans votre fonction de téléchargement
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
}
J'ai eu ce même problème sur mon émulateur API 23 (24 et 25 ont bien fonctionné) en exécutant une application Onglets personnalisés. J'ai essayé cette solution, ainsi que quelques autres variantes, et j'ai pu voir que j'étais en train d'être autorisé mais le problème est resté sur toutes les tentatives de téléchargement. Lorsque j'ai exécuté l'application sur un appareil réel (code de demande sans autorisation), j'ai été automatiquement invité à autoriser Google à accéder au stockage - pas à mon application. J'ai supprimé le code des autorisations d'exécution et défini l'autorisation pour le navigateur (par défaut sur l'émulateur) d'accéder au stockage et mon application a bien fonctionné. Le message suivant a donné un aperçu de ce qui peut se produire avec l'émulateur: La demande et l'autorisation de l'autorisation WRITE_EXTERNAL_STORAGE lors de l'exécution n'a aucun effet sur la session en cours