Android
 Computer >> コンピューター >  >> プログラミング >> Android

【Android】ランタイム権限を使って画像ファイルを外部ストレージに保存する方法

このチュートリアルでは、Androidアプリでランタイム権限(実行時パーミッション)を適切にリクエストしながら、画像ファイルを外部ストレージへ書き込む方法を、サンプルコードとともに段階的に解説します。

手順1:新規プロジェクトの作成

Android Studioで新しいプロジェクトを作成します。メニューから「File」⇒「New Project」を選択し、必要な項目を入力してプロジェクトを作成してください。

手順2:レイアウトファイル(activity_main.xml)の編集

以下のコードを res/layout/activity_main.xml に追加します。

<?xml version = "1.0" encoding = "utf-8"?>
<LinearLayout xmlns:android = "https://schemas.android.com/apk/res/android"
    xmlns:tools = "https://schemas.android.com/tools"
    android:layout_width = "match_parent"
    android:layout_height = "match_parent"
    tools:context = ".MainActivity"
    android:orientation = "vertical">
    <Button
        android:id = "@+id/save"
        android:text = "save"
        android:layout_width = "wrap_content"
        android:layout_height = "wrap_content" />
</LinearLayout>

上記のレイアウトでは、縦方向の LinearLayout の中に「save」というラベルのボタンを1つ配置しています。ユーザーがこのボタンをタップすると、画像データが外部ストレージに保存される仕組みです。

手順3:MainActivity.java の実装

続いて、以下のコードを src/MainActivity.java に追加します。

package com.example.andy.myapplication;

import android.annotation.TargetApi;
import android.content.pm.PackageManager;
import android.graphics.Bitmap;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.os.Bundle;
import android.os.Environment;
import android.support.annotation.NonNull;
import android.support.v4.app.ActivityCompat;
import android.support.v4.content.ContextCompat;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;

import java.io.File;
import java.io.FileOutputStream;

public class MainActivity extends AppCompatActivity {
    private static final int PERMISSION_REQUEST_CODE = 100;
    Button save;
    Bitmap bitmap;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Drawable drawable = getResources().getDrawable(R.drawable.mario);
        bitmap = ((BitmapDrawable)drawable).getBitmap();
        save = findViewById(R.id.save);
        save.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                String state = Environment.getExternalStorageState();
                if (Environment.MEDIA_MOUNTED.equals(state)) {
                    if (Build.VERSION.SDK_INT >= 23) {
                        if (checkPermission()) {
                            String path = Environment.getExternalStorageDirectory().toString();
                            File file = new File(path, "UniqueFileName"+".jpg");
                            if (!file.exists()) {
                                Log.d("path", file.toString());
                                try {
                                    FileOutputStream fos = new FileOutputStream(file);
                                    bitmap.compress(Bitmap.CompressFormat.JPEG, 100, fos);
                                    fos.flush();
                                    fos.close();
                                } catch (Exception e) {
                                    e.printStackTrace();
                                }
                            }
                        } else {
                            requestPermission(); // 権限をリクエスト
                        }
                    } else {
                        // API 23 未満ではマニフェスト宣言だけで書き込み可能
                        String path = Environment.getExternalStorageDirectory().toString();
                        File file = new File(path, "UniqueFileName"+".jpg");
                        if (!file.exists()) {
                            Log.d("path", file.toString());
                            FileOutputStream fos = null;
                            try {
                                fos = new FileOutputStream(file);
                                bitmap.compress(Bitmap.CompressFormat.JPEG, 100, fos);
                                fos.flush();
                                fos.close();
                            } catch (java.io.IOException e) {
                                e.printStackTrace();
                            }
                        }
                    }
                }
            }
        });
    }

    private boolean checkPermission() {
        int result = ContextCompat.checkSelfPermission(MainActivity.this, android.Manifest.permission.WRITE_EXTERNAL_STORAGE);
        if (result == PackageManager.PERMISSION_GRANTED) {
            return true;
        } else {
            return false;
        }
    }

    private void requestPermission() {
        if (ActivityCompat.shouldShowRequestPermissionRationale(MainActivity.this, android.Manifest.permission.WRITE_EXTERNAL_STORAGE)) {
            Toast.makeText(MainActivity.this, "ファイルの保存には外部ストレージへの書き込み権限が必要です。アプリ設定から許可してください。", Toast.LENGTH_LONG).show();
        } else {
            ActivityCompat.requestPermissions(MainActivity.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", "権限が許可されました。ローカルドライブを使用できます。");
                } else {
                    Log.e("value", "権限が拒否されました。ローカルドライブを使用できません。");
                }
                break;
        }
    }
}

処理の流れを解説

ボタンがクリックされると、まず Environment.getExternalStorageState() で外部ストレージの状態を確認し、MEDIA_MOUNTED(読み書き可能な状態)であることをチェックします。

その後、Android 6.0(API 23)以降かどうかで処理を分岐させます。API 23以上の場合は checkPermission() で権限の有無を確認し、まだ許可されていなければ requestPermission() を呼び出してユーザーに権限をリクエストします。API 23未満の端末では、インストール時に権限が付与されるため、直接ファイルを書き込めます。

画像の保存には bitmap.compress(Bitmap.CompressFormat.JPEG, 100, fos) を使用しており、BitmapをJPEG形式(品質100)で圧縮して FileOutputStream 経由でファイルに書き出しています。

権限チェック:checkPermission()

ContextCompat.checkSelfPermission() を使って、WRITE_EXTERNAL_STORAGE 権限がすでに許可されているかどうかを確認し、許可済みなら true を返します。

権限リクエスト:requestPermission()

ActivityCompat.shouldShowRequestPermissionRationale() で、ユーザーに権限が必要な理由を説明すべきかどうかを判定します。説明が必要な場合はToastで案内を表示し、それ以外の場合は requestPermissions() を呼び出してシステム標準の権限ダイアログを表示します。

結果の受け取り:onRequestPermissionsResult()

権限ダイアログでユーザーが選択した結果は、このコールバックメソッドで受け取ります。許可された場合と拒否された場合それぞれに応じて、ログに出力しています。

手順4:AndroidManifest.xml への権限宣言

最後に、以下のコードを manifest.xml に追加します。

<?xml version = "1.0" encoding = "utf-8"?>
<manifest xmlns:android = "https://schemas.android.com/apk/res/android"
    package = "com.example.andy.myapplication">
    <uses-permission android:name = "android.permission.WRITE_EXTERNAL_STORAGE"/>
    <uses-permission android:name = "android.permission.READ_EXTERNAL_STORAGE"/>
    <application
        android:allowBackup = "true"
        android:icon = "@mipmap/ic_launcher"
        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>
    </application>
</manifest>

ここでは WRITE_EXTERNAL_STORAGE(外部ストレージへの書き込み)と READ_EXTERNAL_STORAGE(読み取り)の2つのパーミッションを宣言しています。これにより、OSはアプリがストレージにアクセスすることを認識できるようになります。

アプリの実行と動作確認

それではアプリを実行してみましょう。実機のAndroid端末をPCに接続している前提で進めます。Android Studioから起動するには、プロジェクト内のアクティビティファイルを開き、ツールバーの「Run」アイコンをクリックします。デバイスを選択すると、スマートフォンに次のようなデフォルト画面が表示されます。

【Android】ランタイム権限を使って画像ファイルを外部ストレージに保存する方法

上記の画面で「save」ボタンをタップすると、以下のように画像が外部ストレージに保存されます。

【Android】ランタイム権限を使って画像ファイルを外部ストレージに保存する方法

補足:Android 10以降のスコープドストレージについて

Android 10(API 29)以降ではスコープドストレージが導入され、Environment.getExternalStorageDirectory() による共有ストレージへの直接アクセスは非推奨となっています。最新のOSバージョンをターゲットにする場合は、MediaStore APIや getExternalFilesDir() を利用した保存方法を検討するとよいでしょう。

  1. SDカードのフォルダ・ファイルにAndroidの書き込み権限を設定する方法【サンプルコード付き】

    本記事では、AndroidアプリからSDカード(外部ストレージ)上のフォルダやファイルに対して書き込みを行うために必要なアクセス許可(パーミッション)の設定方法を、サンプルコード付きで解説します。「テキストを入力して外部ストレージに保存し、あとで読み出す」というシンプルなアプリを題材に、レイアウト・Javaコード・マニフェストの実装手順を順番に見ていきましょう。 実装の全体像 外部ストレージへの読み書きを実現するには、主に次の3つの要素が必要です。 マニフェストでの権限宣言:READ_EXTERNAL_STORAGE と WRITE_EXTERNAL_STORAGE を宣言する ストレージ

  2. Rubyでファイルを読み書きする方法を実例つきで徹底解説

    Rubyでファイルの読み書きができるようになると、ファイルからデータを抽出したり、新しいファイルを作成したり、必要な情報を素早く見つけたりできるようになります。この記事では、Rubyにおけるファイル操作の基本を、実際のコード例とともにわかりやすく解説します。 この記事で学べること Rubyでファイルを読み込む方法 Rubyでファイルに書き込む方法 覚えておきたいFileクラスのメソッド ディレクトリ操作の基礎 FileUtilsモジュールの使い方 まとめ それでは始めましょう! Rubyでファイルを読み込む方法 Rubyでファイルを読み込む基本的な流れは、次の3ステップです。 op