Android DownloadManagerを使用してサンプルをダウンロードするアプリPDFファイルをDownloadディレクトリにプログラムしました。コードは次のとおりです。
@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 Studioからデバッグ実行しようとしましたAndroid 6.0。ダウンロードボタンをクリックすると、このエラーが発生します。
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'、トランスポート: 'socket'
(3行目)は、外部ストレージへの書き込み権限がないことを示しています。
しかし、私の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);
READ_EXTERNAL_STORAGEおよびWRITE_EXTERNAL_STORAGE権限がManifest.xmlファイルにあることを確認します。
そして、このコードをダウンロード関数に含めます
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
}
カスタムタブアプリを実行しているAPI 23エミュレーター(24と25で問題ありません)で同じ問題が発生しました。このソリューションと他のバリエーションを試したところ、許可が与えられていたことがわかりましたが、ダウンロードの試行で問題が残っていました。実際のデバイスでアプリを実行すると(許可リクエストコードなし)、アプリではなくストレージへのGoogleアクセスを許可するように自動的に求められました。ランタイムパーミッションのコードを削除し、ブラウザ(エミュレータのデフォルト)にストレージにアクセスするためのパーミッションを設定すると、アプリは正常に機能しました。次の投稿は、エミュレータで何が起こっているかについての洞察を提供しました: 実行時にWRITE_EXTERNAL_STORAGEパーミッションをリクエストして許可しても、現在のセッションには影響しません