公開領域にアクセスするには(AndroidMode編)

◆PROCESSING 逆引きリファレンス

 カテゴリー:スマホ(AndroidMode)

公開領域にアクセスするには(AndroidMode編)

【概要】

PROCESSINGにAndroidMode を導入する事で、PROCESSINGで開発したプログラムをAndroid端末上で動かす事ができるようになります。

AndroidModeの導入については「PROCESSINGをAndroid端末で動かすには(4.0版)」記事を参照してください。

AndroidスマホにはNAND型のフラッシュメモリを利用したストレージが搭載されている事が多いようですが、Androidのストレージ領域は

  • 内部領域(getFilesDirectory)
  • 外部領域(getExternalFilesDirectory)
  • 公開領域(getExternalStoragePublicDirectory)

と呼ばれる3つの領域から構成されています※。()内はこの領域にアクセスする代表的なAPIです。

※実際には、これにキャッシュ領域が加わります。


(画像URL:illust-AC 様:shinya さん、acworks さん)

本記事では、このうち公開領域と呼ばれるエリアにアクセスする方法について紹介します。

内部領域と外部領域にアクセスする方法については「ストレージのファイルをアクセスするには(AndroidMode編)」記事を参照してください。

公開領域は、アプリケーションが他のアプリケーションと情報を共有するための領域です。(必ずではありませんが)この領域はSDカード上に確保されることがあります。

当然ですが「公開領域」には個人情報や、勝手に読み書きされては困るファイルは置いてはいけません。

公開領域にアクセスするには特別な権限が必要となります。またこの領域はAndroid 6.0以降、セキュリティの観点からアクセスが厳しく制限されるようになっています。

例えば読み込みを行うのであれば、マニフェストファイルに

を追記する必要があります。

書き込みを行うのであれば

を追記します。

上記はマニフェストファイルに外部ストレージへのアクセス権を追記した例です。書き込み権限を与えると、読み取りも可能になる事に注意してください。

標準エディタで開発している場合は Androidメニューから「Sketch Permissions」を選択して開くダイアログボックスで WRITE_EXTERNAL_STORAGE などにチェックをつけてください。

またAndroid6.0以降では、公開領域へファイルを書き込んだり、フォルダを作成するには、マニフェストファイルにパーミッションを記述するだけでは不十分となりました。

とくに古い参考書やブログの記事では、マニフェストファイルにパーミッションを記述するだけでアクセスできるように書いてあるものがあります(当時はウソでは無かった:汗)ので、注意してください。

また公開領域は、外部領域と同じく「必ず読み書きできる」とは限りません。公開領域がSDカードなどである場合、ユーザによって取り外される事があるからです。

より慎重にプログラミングするなら、 Environment がもつ getExternalStorageState() メソッドで、公開領域の状態を確認してから操作するのが良いでしょう。

Android 6.0 以降で、公開領域にアクセスする最もシンプルなケースでは

  • アクセスしたい領域へのパス、またはFileオブジェクトを得る
  • アクセス可能か検査する
  • 必要な権限があるか確認する
  • 権限がない場合は、権限を要求する
  • 権限の要求結果を受け取って処理する

という流れになります。

また必要に応じて「なぜ権限が必要なのか説明する」手順を加えることが推奨されています。

 

【詳細】

ファイルオブジェクトを取得する

公開領域は、Environment がもつ getExternalStoragePublicDirectory()  メソッドでFileオブジェクトが取得可能です。
.

公開領域へのFileオブジェクト取得File file =  Environment . getExternalStoragePublicDirectory( String type ) ;

Environment : Environmentクラス
file : 公開領域の Fileオブジェクト
type : 領域を識別するための名前。null は不可

type には、Environmentクラスが持つ以下の定数の何れか、または任意のフォルダ名を指定します。

DIRECTORY_MUSIC
DIRECTORY_PODCASTS
DIRECTORY_RINGTONES
DIRECTORY_ALARMS
DIRECTORY_NOTIFICATIONS
DIRECTORY_PICTURES
DIRECTORY_MOVIES
DIRECTORY_DOWNLOADS
DIRECTORY_DCIM
DIRECTORY_DOCUMENTS

各定数ごとに、公開領域のしかるべき File オブジェクトが戻されます。

<出力例>

上記例は、公開領域のDCIM領域(写真などを格納するフォルダ)に関するパスを取得して表示するものです。

 

権限があるか確認する

checkSelfPermission() メソッドで、必要な権限を該当アプリケーションが持っているかどうかが確認できます。
.

権限を確認するint check = ContextCompat . checkSelfPermission (Context context, String permission);
int check = act . checkSelfPermission (String permission);

check : 権限の有無。 PERMISSION_GRANTED、PERMISSION_DENIED の何れか
context : アプリケーションコンテキスト
permission : 確認したい権限名
act : Activityインスタンス

permission には、確認したい権限名を指定します。権限名には Manifest.permission クラスが持つ定数を利用します。

例えば、外部ストレージへのアクセス権なら「Manifest.permission.WRITE_EXTERNAL_STORAGE」です。

下記は、外部ストレージへのアクセス権があるか検査するサンプルです。

実は checkSelfPermissionメソッドは、ContextCompat クラス、PermissionChecker クラス、Context クラスにもあります。ややこしいですね(汗)。

PROCESSINGをAndroidStudioで開発するなら何れのメソッドも利用可能ですが、ContextCompat クラスのものを使えば良いかと思います。

ただし標準エディタで開発する場合は、標準エディタが android.support.v4 ライブラリを  import できないため、Context がもつ checkSelfPermissionメソッド一択となります。

それぞれ細かい動作が異なるのですが、違いが知りたい方は以下のブログ等が参考になります。私も大いに参考とさせていただきました。ありがとうございます。

 

権限を要求する

権限がない場合は、必要な権限をユーザに要求する必要があります。

権限の要求には requestPermissions() メソッドを利用しますが、このメソッドもActivityCompat クラスとActivity クラスの両方にあります。
.

権限を要求するvoid ActivityCompat . requestPermissions (Activity act, String[] permissions, int requestCode);
void act . requestPermissions (String[] permissions, int requestCode);

permission : 確認したい権限名
requestCode : 一意に決めた任意の数値
act : Activityインスタンス

checkSelfPermissionと同じように、PROCESSINGをAndroidStudioで開発するなら、ActivityCompat クラスのものを使えば良いでしょう。

標準エディタで開発する場合は、Activity がもつ requestPermissions メソッド一択となります。

permission には、取得したい権限名を指定します。権限名には Manifest.permission クラスが持つ定数を利用しますが、こちらは文字列配列となっています。

なぜ配列かといえば、1回の命令で複数の権限を要求できるからです。

上記は外部ストレージへのアクセス権を要求する例です。

アプリケーションを起動して、最初にrequestPermissions() を発行すると、以下のようなダイアログBOXが表示されて権限の要求が行われます。

表示されるメッセージは、要求する権限により異なります。

ここで「許可」または「許可しない」を選択すると、onRequestPermissionsResult にrequestCodeで与えたコードとともに、選択結果がパラメータとして渡されます。

onRequestPermissionsResult では、権限の許可・非許可に応じて適切な処理を行うことになるでしょう。

最初のアプリケーション起動で権限が与えらなかった場合、2度目にアプリケーションの起動を行って requestPermissions() を発行すると、今度は以下のようなダイアログBOXが表示されます。

1度目とは違い「今後は確認しない」というチェックBOXがあります。

「今後は確認しない&許可しない」を選択した場合、以降はrequestPermissions()を発行しても、再び問い合わせメッセージが表示される事はなく、要求した権限が無い状態となります。

注意としては、2018/8月現在 requestPermissions()をPROCESSINGのAndroidMode標準の仮想端末で実行すると、プログラムが異常終了する事です(汗)。

同じコーディングをAndroidStudioから、普通の(AndroidStudioの仮想端末マネージャ経由で作成した)仮想端末で実行すると、正常に動作します。AndroidMode標準の仮想端末の不具合かとは思いますが、標準エディタでプログラムをテストする方は注意してください。

「今後は確認しない&許可しない」を選択された後、再度権限を要求するダイアログボックスを表示するには

設定→アプリと通知→アプリの権限→ストレージ  で表示されるストレージ権限一覧から、目的のアプリケーションを探し出して、右横のスィッチをON→OFFと切り替えます。


もちろんこの操作でスィッチをON=権限付与 状態のままにしたら、以降は checkSelfPermission() で「権限あり」が戻ってきます。

 

権限の要求結果を受け取る

requestPermissions()の結果は、onRequestPermissionsResult で受け取ります。

上記はonRequestPermissionsResult で権限要求結果を受け取る例です。

requestCodeには、requestPermissionsに与えたコードが渡ってくるので、どのrequestPermissionsの結果なのかを判定可能です。

permissionsには、ユーザによって処理された権限名が渡ってきます。grantResultsはユーザの選択結果です。

それぞれ配列なのは、requestPermissionsが複数の権限を一度に要求できるためです。

 

権限取得理由を説明する

より親切に作るなら、権限を要求するときには、なぜその権限が必要なのかユーザに丁寧に説明すべきでしょう。

カメラアプリがカメラアクセス権を要求するのは自然ですが、カメラアプリが電話帳へのアクセス権を要求するとなれば、違和感がありますよね?

そんな場合は、「なぜその権限が必要なのか」ちゃんと説明すべきです。

Androidにはこのような利用を想定して、shouldShowRequestPermissionRationaleメソッドが用意されています。

shouldShowRequestPermissionRationaleメソッドは、該当アプリが初めて権限を要求する時はFalseを返しますが、2度目以降の権限要求時で、かつ「今後は確認しない&許可しない」で拒否されていない場合は、Trueを返します。

このメソッドが True を返したときは、「少なくとも1回以上、権限の要求を拒否された状態」だが、まだ「今後は確認しない&許可しない=2度と聞くんじゃねーよ」が選ばれたわけではない状態だという事です。

なので、親切丁寧に「権限が必要な理由」を説明する必要があると判断します(笑)。
.

説明の必要性を確認するboolean ret = ActivityCompat . shouldShowRequestPermissionRationale(act, String permissions);
boolean ret = act . shouldShowRequestPermissionRationale(String permissions);

permission : 確認したい権限名
ret : False 初回または永久拒否状態。True 2回目以降で問い合わせ可能状態
act : Activityインスタンス

このメソッドも ActivityCompat 版 と Activity 版があります。言うまでもなく、標準エディタでコーディングする人はActivity版一択です。

上記は先程のサンプルに、shouldShowRequestPermissionRationaleを組み込んだ例です。

この例はサンプルなので、ちょっと乱暴な方法でダイアログボックスを表示していますが、このダイアログボックス表示方法は非推奨です。ちゃんとしたアプリでは真似してはいけません。

メッセージの内容は・・・まぁ気にしないでください。ええ。サンプルですので。(汗)。

 

【関連記事】

 


サンプルプログラム

ストレージのアクセス権を要求する例:

詳細で細切れに説明した内容をまとめたサンプルです。
公開領域は、必ずアクセスできるとは限らないし、フォルダがあるとも限らないため、必要な処理を行っています。

本サンプルでは公開領域にオリジナルのフォルダ(MYAPPLICATION)を作成し、そこに勇者のパーティメンバーを書き込んでいます。

<出力サンプル>


PROCESSING逆引きリファレンス一覧 へ戻る

本ページで利用しているアイコン画像は、下記サイト様より拝借しております。各画像の著作権は、それぞれのサイト様および作者にあります。