fc2ブログ
ヽ|∵|ゝ(Fantom) の 開発blog? ホーム »Android
カテゴリー「Android」の記事一覧

【Android】Android 11 (API 30) 以降でメディアファイル(画像/音楽 等)以外をアプリで使う  


 VRM Live Viewer でも「.vmd が読み込めなくなった」のような質問が多くなったのだが、ずっと外部サイトの情報を参考にしていたんだよね。

(参考) Android 11で画像やデータが消えた、アクセスできない、の原因はアクセス権限の変更、対処法アリ

 でも、最近 Android 13 に換えたので、実際に試してみると、上記の方法だけでは足りない事がわかった。きちんと調べてみると、Android 11 以降は「メディアファイル(画像/音楽など)」と「それ以外のファイル」で扱いが異なっていて、VRM や GLB、VMD などは「それ以外のファイル(メディア以外のファイル)」に分類されてしまうため、アクセス制限がされてしまうらしい(画像/音楽などは上記の方法でも使える)。

 試しに「ストレージ デバイスのすべてのファイルを管理する」権限を与えてみた所、「それ以外のファイル(VRM や GLB、VMD 等)」も読み込めるようになったので、一応、一般ユーザー向けと開発者向けとして、具体的手順(例)を載せておこう。

ストレージ デバイスのすべてのファイルを管理する


(※) Galaxy Android 13 (API 33) / VRM Live Viewer v3.7 で確認



■Android 端末での手順 (一般ユーザー向け)

※機種(端末)やバージョンによって文言は違うかも知れません。
* The wording may differ depending on the model (device) or version.


1. [設定] から [セキュリティおよびプライバシー] をタップする
From [Settings], tap [Security and privacy]



2. [セキュリティおよびプライバシー] から [プライバシー] をタップする
From [Security and privacy], tap [Privacy]



3. [プライバシー] から [権限マネージャー] をタップする
From [Privacy], tap [Permission manager]



4. [権限マネージャー] から [ファイルとメディア] をタップする
From [Permission manager], tap [Files and media]



5. [ファイルとメディア] から [すべてのファイルにアクセスできるアプリをもっと見る] をタップする
From [Files and media], tap [See more apps that can access all files]



6. [全てのファイルにアクセスできるアプリ] の一覧から、対象のアプリを探しオンにする(ここでは VRM Live Viewer を例にしてるが、アプリ側にも権限を与える必要がある)。
From [All files access], Find the app you want and turn it on.



 これでメディアファイル(画像/音楽 等)以外のファイルもアプリでアクセスできるようになる(~アクセスを許可しますか?で許可にしたときのみ)。

 また Android 11 以降では、しばらくアプリを使用していないと自動的に権限削除されるようになったらしい。その場合は毎回許可 or 設定しなければならないので、アプリのアイコンを長押しし、[アプリ情報] からアプリ自体の [アプリが未使用の場合に権限を削除] をオフにしておくと良い。



 どうやら Google は今後 SDカード等、外部ファイルを読み込ませるのを少しでもやめさせ、ネットサービス等で落としたもの(VRoidHub 連携などは普通に使える)を中心にしたいらしいね。画像や音楽などはともかく、それ以外のファイルの扱いについては、まだまだセキュリティ強化の名目で使いづらくなりそうだ。



■Android でのパーミッションやインテント等 (開発者向け)

※「すべてのファイルを管理」パーミッションを付与した場合、Google Play で審査が通らなくなる場合があるようです。ファイルマネージャーやバックアップアプリなど、特定の用途以外のアプリでの利用は注意して下さい。

Google Play に関する注意事項

●「すべてのファイルを管理」のパーミッション (AndroidManifest.xml)
<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" />


(参考) すべてのファイルへのアクセスをリクエストする

●インテント (ユーザーをシステム設定のページに移動)
ACTION_MANAGE_ALL_FILES_ACCESS_PERMISSION 




 めっちゃ面倒くさい…。ただの偶然だが、Google Play に出さなくて良かった気がする(←無料アプリでも登録料必要なのが馬鹿馬鹿しくてやらなかっただけ(笑))。







スポンサーサイト



category: Android

tb: 0   cm: --

【Android】SQLite の内容をサクッとコマンドプロンプトで確認する  


 SQLite のデーターベースの中身を確認するには、DB Browser for SQLite みたいなGUIツールもあるみたいだが、開発中にサクっとコマンドプロンプトで内容確認したいときの手順。どちらかと言うと自分用メモ。

(※) Android Studio 3.4.1 / Windows10(x64) で確認



■簡易的な手順

1.Android Studio からエミュレータを起動(Tools>AVD Manger または Run>Run [アプリ名] など)。

2.コマンドプロンプトを起動。

3.コマンドプロンプトで、
adb shell

で、ADBを起動(パスが通ってなかったら、Android SDK をインストールしたフォルダ以下の「platform-tools」フォルダに「adb.exe」があるので、起動する)。

4.ADB の shell で、
run-as [パッケージ名]

で、アプリのデータ領域を確認できるようになる(※パッケージ名とは「com.company.application」みたいなアプリのIDとなるもの)。

5.そのまま ADB の shell で、
cd databases

で、データーベースフォルダへ移動

6.次に ADB の shell で、
sqlite3 [データーベース名]

で、データーベースに接続(※データーベース名は「mydatabase.db」みたいな、自分で付けた名前)。

7.sqlite コマンドで、
.table

で、既存のテーブルを確認(※sqlite コマンドは頭に "." (ピリオド) を付ける)。

8.sqlite コマンドで、
.schema [テーブル名]

で、スキーマ(テーブルの構造など)を確認。

9.sqlite コマンドで、
.headers on

で、カラム表示にヘッダーを付ける(※off で消える)。

10.sqlite コマンドで、
.mode column

で、カラム表示形式を見やすくする(※無いときは "|" (パイプ) で表示)。

11. SQL 文で、
select * from [テーブル名];

で、テーブルの中身を確認(※SQL 文の場合は、最後に ";" (セミコロン)を付ける。付け忘れて "...>" みたいに出たら、";" だけ [Enter] すれば良い)。

12. sqlite コマンドで、
.exit

で、終了。

.help でヘルプが見れます。


(参考)
【Android】SQLiteデータベースの中身を確認する
[Android Studio] データベースの中身を直接確認する
[Android] SQLiteのデータを確認する方法
SELECT文の結果を表示する時にカラム名をヘッダーとして表示(.headersコマンド)





(関連記事)
【AndroidStudio】AndroidStudio 2.x で DDMS を表示する
【Android】【Java】エラーをSDカードに書き出す


category: Android

thread: ソフトウェア開発

janre: コンピュータ

tag: Android資料  開発ツール 
tb: 0   cm: --

【Android】【Java】パーミッションの付与(許可)のチェックと要求をする  


 Android 6.0 以降からは実行時のパーミッションリクエストができるが、ググったら「ContextCompat」(または「ActivityCompat」)での例がほとんどだったので、敢えて「~Compat」を使わない実装を書いておこうと思った。実際に「~Compat」はサポートライブラリが必要となるので、使えない環境で書きたい場合もあるだろう。もちろん Android6.0(API 23)以降になってしまうが、私も Unity のプラグインでは今回の方法を用いている(サポートライブラリ等、他のライブラリを入れるとファイルサイズも大きくなるため、ほぼ全ての実装を自前でやっている)。

 なので「~Compat」で書きたい場合は、公式のデベロッパーマニュアルに載っているので、そちらの方を見れば良いだろう(基本的には同じ内容である)。

(参考)
実行時のパーミッション リクエスト


(※) Android Studio 3.1.2 / Galaxy S7 Edge (Android 7.0) / Windows10(x64) で確認



■パーミッションの許可/拒否をチェックする(static メソッド)

 ここでは汎用的に使えるように、static で定義したものを書いておこう。ライブラリとして保存しておけば使い回しも簡単にできる。

●パーミッションの許可/拒否をチェックする(static メソッド)
import android.content.Context;
import android.content.pm.PackageManager;

//パーミッションの許可(付与)チェック
public static final boolean checkPermission(final Context context, final String permission) {
final PackageManager pm = context.getPackageManager();
return (pm.checkPermission(permission, context.getPackageName()) == PackageManager.PERMISSION_GRANTED);
}

●使用例(メインでのコードなど)
import android.util.Log;

//※アクティビティでの使用例
boolean granted = checkPermission(this, "android.permission.WRITE_EXTERNAL_STORAGE"); //this は Context
Log.d("DebugTag", "granted = " + granted);

granted = false (または true)

 ここでの結果はパーミッションが許可(付与)されてない状態として false が返ってきているが、元々許可されている場合は true になる。ちなみに「READ_EXTERNAL_STORAGE」(ストレージのファイル読み取り権限)というものもあるが、これは「WRITE_EXTERNAL_STORAGE」(ストレージのファイル読み書き権限)が許可されていれば、true になる。

 また「AndroidManifedt.xml」での書き方は、基本的に <manifest>~</manifest> タグの中に書く。以下に例を挙げておこう。

●AndroidManifedt.xml に「WRITE_EXTERNAL_STORAGE」パーミッションを書く例
<manifest ~・・・(略)・・・ >
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

・・・(略)・・・
</manifest>

 パーミッション自体の文字列定数は公式のデベロッパーマニュアルを見て欲しい。

(参考)
Manifest.permission (Constant Value を使う)
<uses-permission> (name 属性だけでも良い)



■パーミッションのチェックとその理由→要求をする(インスタンス メソッド)

 次にリアルタイムにパーミッションをチェックし、必要なら(許可されてなければ)そのパーミッションが必要な理由と要求ダイアログを出す方法をやってみよう。またここでは前述した static な checkPermission() を使っても良いが、単一のアクティビティ上での実装として、インスタンスメソッドで書くことにしよう。実際には static で書いても構わない(ちなみに Unity のプラグインは static で書いてある)。

●パーミッションのチェックとその理由→要求をする(※アクティビティでの実装例)
import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.pm.PackageManager;
import android.widget.Toast;

//定数など
//https://developer.android.com/reference/android/Manifest.permission.html
private static final String PERMISSION_WRITE_EXTERNAL_STORAGE = "android.permission.WRITE_EXTERNAL_STORAGE"; //ストレージの読み書き権限
private static final int REQUEST_WRITE_EXTERNAL_STORAGE = 1; //※番号は任意:onRequestPermissionsResult() で合わせる

//パーミッションの許可(付与)チェック
//https://developer.android.com/training/permissions/requesting#perm-check
private boolean checkPermission(String permission) {
final PackageManager pm = getPackageManager();
return pm.checkPermission(permission, getPackageName()) == PackageManager.PERMISSION_GRANTED;
}

//パーミッションの根拠と要求(API 23 [Android 6.0])
//https://developer.android.com/training/permissions/requesting#make-the-request
private void showPermissionRationaleAndRequest(final String permission, final int requestCode) {
if (android.os.Build.VERSION.SDK_INT >= 23) { //Android 6.0

//パーミッション要求の根拠の説明を必要とするか?「今後表示しない」をチェックすると常に false になる。
boolean isShouldRationale = shouldShowRequestPermissionRationale(permission); //API 23 (Android 6.0)
if (isShouldRationale) {
//根拠の説明ダイアログを必要とするとき
AlertDialog.Builder builder = new AlertDialog.Builder(this); //this は Context //※この実装では画面回転で消えるので注意
builder.setTitle("以下の理由で○○の権限が必要です。")
.setMessage("・説明1\n・説明2\n・説明3")
.setPositiveButton("OK", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
requestPermission(permission, requestCode);
}
})
.show();
} else {
//根拠の説明ダイアログ不要のとき
requestPermission(permission, requestCode);
}
}
}

//パーミッションを要求する(API 23 [Android 6.0])
private void requestPermission(String permission, int requestCode) {
if (android.os.Build.VERSION.SDK_INT >= 23) { //Android 6.0
requestPermissions(new String[]{ permission }, requestCode);
}
}

//パーミッション要求の結果コールバックハンドラ(API 23 [Android 6.0])
//https://developer.android.com/training/permissions/requesting#handle-response
@Override
public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) {
switch (requestCode) {
case REQUEST_WRITE_EXTERNAL_STORAGE: {
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
Toast.makeText(this, "ユーザーによってストレージ読み書き権限が許可されました。", Toast.LENGTH_SHORT).show(); //this は Context
} else {
Toast.makeText(this, "ユーザーによってストレージ読み書き権限が拒否されました。", Toast.LENGTH_SHORT).show(); //this は Context
}
return;
}
}
}

●使用例(メインでのコードなど)
import android.util.Log;

//※アクティビティでの使用例
boolean isGranted = checkPermission(PERMISSION_WRITE_EXTERNAL_STORAGE); //現在のパーミッションをチェック
Log.d("DebugTag", PERMISSION_WRITE_EXTERNAL_STORAGE + "\nisGranted = " + isGranted);

if (!granted) {
//パーミッションが付与されてないとき、根拠の説明と要求をする(ダイアログを出す)
Log.d("DebugTag", PERMISSION_WRITE_EXTERNAL_STORAGE + ", requestCode = " + REQUEST_WRITE_EXTERNAL_STORAGE);
showPermissionRationaleAndRequest(PERMISSION_WRITE_EXTERNAL_STORAGE, REQUEST_WRITE_EXTERNAL_STORAGE); //API 23 (Android 6.0)
}


 注意して欲しいのはあくまでも、あらかじめ「AndroidManifest.xml」に書かれているパーミッションでしか要求はできないという点だ。その書き方は前述の「AndroidManifest.xml にパーミッションを書く例」を参考にして欲しい。

 根拠の説明ダイアログは「AlertDialog」を利用しているが、このままでは画面回転などで消えるので注意して欲しい。今回はテーマから外れるので必要あればデベロッパーマニュアルなどを参照して欲しい。またダイアログ内のメッセージも手抜きしているが(笑)、権限によって内容を変えるにはあらかじめメッセージを定義しておくことも必要だろう。リクエストコード(requestCode)は任意なので、その辺りで紐づけしても良いかも知れない。

 またこの実装では2つ以上同時に権限要求すると、ダイアログが重なってしまうという欠点もある。もしそういう必要があるなら、要求を Queue のようなもので管理すると良い(LinkedList 等でも可)。ちょっと難しいかも知れないが、挑戦してみるのも良いだろう。


(参考)
ダイアログを表示する
実行時のパーミッション リクエスト
パーミッションの確認
必要なパーミッションのリクエスト
パーミッション リクエストへの応答の処理





(関連記事)
【Android】【Java】AlertDialog を使ってみる
【Android】【Java】WIFI接続ONを取得する
【Android】【Java】WIFI, Bluetooth 接続の暗黙的Intent
【Android】【Java】SDカードからテキストファイルを読み込む
【Android】【Java】SDカードから画像ファイルを読み込む
【Android】【Java】SDカードに画像ファイルを保存する(png)
【Android】【Java】SDカードに画像ファイルを保存する(jpg)
【Android】【Java】SDカードのファイルを削除する


category: Android

thread: プログラミング

janre: コンピュータ

tag: Androidライブラリ  Androidリファレンス  Java 
tb: 0   cm: --

【Android】【Java】アプリ名、バージョン番号(versionCode)、バージョン名(versionName) などをコードで取得する(PackageManager を利用)  


 前回 "app_name" など、リソースからIDを取得→アプリ名取得する方法などを書いたが、PackageManager からもアプリの情報などを取得することができる。ついでなので、バージョン番号(versionCode)バージョン名(versionName)ビルドターゲットSDKのバージョン(targetSdkVersion)最小SDKバージョン(minSdkVersion)なども書いておこう。これらの違いは簡単な解説も書いておくが、以下に資料を載せておくので必要なら確認して欲しい。

(参考)
Android での API レベルの使用
minSdkVersionとtargetSdkVersionの関係


(※) Android Studio 3.1.2 / Galaxy S7 Edge (Android 7.0) / Windows10(x64) で確認



■アプリケーション名を取得する

import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;

//アプリケーション名を取得する
public static final String getApplicationName(final Context context) {
try {
final PackageManager pm = context.getPackageManager();
final ApplicationInfo info = pm.getApplicationInfo(context.getPackageName(), 0);
return pm.getApplicationLabel(info).toString();
} catch (PackageManager.NameNotFoundException e) {
return ""; //取得失敗
}
}

●使用例(メインでのコードなど)
import android.util.Log;

//※アクティビティでの使用例
String applicationName = getApplicationName(this); //this は context
Log.d("DebugTag", "applicationName = " + applicationName);

applicationName = AppInfoTest

 アプリ名はローカライズされた文字列となる。ここでは自身のパッケージ名を使っているが、パッケージ名を引数に加えたオーバーロードでも作れば、他のアプリの名前も取得できる。

 またなぜかデベロッパーマニュアルには載ってないが、以下のようにしても取得できるようだ。
final PackageManager pm = context.getPackageManager();
final ApplicationInfo info = pm.getApplicationInfo(context.getPackageName(), 0);
return info.loadLabel(pm).toString(); //なぜかマニュアルにはない?




■バージョン番号(int 型)を取得する

import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;

//バージョン番号(int 型)を取得する
//・1 以上のときバージョン番号 / 0 = パッケージが存在しない
public static final int getVersionCode(final Context context) {
try {
final PackageManager pm = context.getPackageManager();
final PackageInfo info = pm.getPackageInfo(context.getPackageName(), PackageManager.GET_META_DATA);
return info.versionCode;
} catch (PackageManager.NameNotFoundException e) {
return 0; //取得失敗
}
}

●使用例(メインでのコードなど)
import android.util.Log;

//※アクティビティでの使用例
int versionCode = getVersionCode(this); //this は context
Log.d("DebugTag", "versionCode = " + versionCode);

versionCode = 1

 バージョン番号とは常にインクリメントしていく、整数値の番号である。高いバージョンがインストしてある端末には低いバージョンをインストすることができない。その場合は高いバージョンをアンインストすれば、低いバージョンをインストすることができる。Google Play などに提出する際は低いバージョンをアップロードできないので注意しよう。

(参考)
Android での API レベルの使用



■バージョン名(String 型)を取得する

import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;

//バージョン名(String 型)を取得する
//・取得成功 = "1.0.0" など / 取得失敗 = ""
public static final String getVersionName(final Context context) {
try {
final PackageManager pm = context.getPackageManager();
final PackageInfo info = pm.getPackageInfo(context.getPackageName(), PackageManager.GET_META_DATA);
return info.versionName;
} catch (PackageManager.NameNotFoundException e) {
return ""; //取得失敗
}
}

●使用例(メインでのコードなど)
import android.util.Log;

//※アクティビティでの使用例
String versionName = getVersionName(this); //this は context
Log.d("DebugTag", "versionName = " + versionName);

versionName = 1.0

 バージョン名とはユーザーに伝えるバージョンのことである。文字列なので "1.0.0" とか "2.0b" など自由に設定できる。番号を上下することはできるが、ユーザーに混乱をもたらすので普通はやらない方が良いだろう。

(参考)
Android での API レベルの使用



■ビルドターゲットSDKバージョン(API Level)を取得する

import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;

//ビルドターゲットとするSDKのバージョン(API Level)を取得する
//・1 以上のときバージョン番号 / 0 = 取得失敗
public static final int getTargetSdkVersion(final Context context) {
try {
final PackageManager pm = context.getPackageManager();
final ApplicationInfo info = pm.getApplicationInfo(context.getPackageName(), 0);
return info.targetSdkVersion;
} catch (PackageManager.NameNotFoundException e) {
return 0; //取得失敗
}
}

●使用例(メインでのコードなど)
import android.util.Log;

//※アクティビティでの使用例
int targetSdkVersion = getTargetSdkVersion(this); //this は context
Log.d("DebugTag", "targetSdkVersion = " + targetSdkVersion);

targetSdkVersion = 27

 ターゲットSDKのバージョンとはアプリをビルド(コンパイル)する際に利用するSDKのバージョン(API Level)のことである。利用するクラスやメソッドによっては、この条件(API Level)を満たしてないとコンパイルエラー(というより、エディタ上でエラーが出る)でビルドできない。

(参考)
minSdkVersionとtargetSdkVersionの関係



■最小SDKバージョン(API Level)を取得する

import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;

//実行できる最小SDKバージョン(API Level)を取得する (API 24 以上)
//・1 以上のときバージョン番号 / 0 = 取得失敗 (API 24 より下は常に0)
public static final int getMinSdkVersion(final Context context) {
if (Build.VERSION.SDK_INT < 24)
return 0; //未対応

try {
final PackageManager pm = context.getPackageManager();
final ApplicationInfo info = pm.getApplicationInfo(context.getPackageName(), 0);
return info.minSdkVersion; //API 24
} catch (PackageManager.NameNotFoundException e) {
return 0; //取得失敗
}
}

●使用例(メインでのコードなど)
import android.util.Log;

//※アクティビティでの使用例
int minSdkVersion = getMinSdkVersion(this); //API 24 / this は context
Log.d("DebugTag", "minSdkVersion = " + minSdkVersion);

minSdkVersion = 24

 最小SDKバージョンとは利用できる端末の最小のSDKのバージョン(API Level)のことである。この例では 24 となっているが、これは Android 7.0 のことであり、それより下の端末(Android 6.0 とか 5.0 とか)は使えないという意味である。バージョン(API Level)を上げれば色々な機能を使えるようになるが、対応できる端末は少なくなるので注意が必要である。例えば ARCore などは「require Android 7.0 or later」となっているので、6.0以下などは利用できない。そういうアプリを作るときには重要になる。

 ただし、このメソッド自体(正確には ApplicationInfo.minSdkVersion 自体)が API Level 24 (Android 7.0) 以降でしか使えないので注意しよう(6.0以前は常に 0 になる)。

(参考)
minSdkVersionとtargetSdkVersionの関係





(関連記事)
【Android】【Java】テーマ(スタイル)等のリソースID(int値)を文字列から取得する
【Android】【Java】アプリ名 app_name タグをコードで取得する
【Android】【Java】画像リソースIDをコードで取得する
【Android】【Java】リソース名で、res/drawable-~ フォルダから、画像を読み込む(Bitmap)
【Android】【Java】リソース名で、res/drawable-~ フォルダから、画像を読み込む(Drawable)
【Android】【Java】res/raw リソースフォルダからテキストファイルを読み込む


category: Android

thread: プログラミング

janre: コンピュータ

tag: Androidライブラリ  Java 
tb: 0   cm: --

【Android】【Java】テーマ(スタイル)等のリソースID(int値)を文字列から取得する  


 Android Studio 内で完結するアプリなら必要ないかも知れないが、外部とのアプリ連携やプラグインのような別のシステムから、何らかのリソースを利用したいこともある。その場合、文字列からリソースID("android.R.~" や アプリ内の "R.~" の int値)を取得して適用することによって、Android 内のリソースを利用することができる。そのリソースID取得の方法を簡単にまとめておこう。なお今回は「テーマ(スタイル)の ID」と書いてはあるが、汎用的に使えそうなメソッドも提供しておくので、"mipmap" や "drawable", "string" なども応用すれば使える。その例もいくつか挙げておこう。


(※) Android Studio 3.1.2 / Galaxy S7 Edge (Android 7.0) / Windows10(x64) で確認



■テーマ(スタイル)の ID(int値)を文字列から取得する

 通常、Android Studio 内で開発している分には、スタイル(テーマ)は「android.R.style.Theme_DeviceDefault_Light_Dialog_Alert」(またはアプリ独自の場合「(パッケージ名).R.~」)のように、システムが用意した定数をハードコーディングしておけば事足りる。しかし動的に変更したり、何らかで ID(int値)が必要になった場合(Android のシステム関数の場合、リソースIDが引数になってるものも多い)、文字列から ID に変換できると便利だ。ちなみに私は Unity から Android のネイティブダイアログを使えるプラグインをリリースしているが、このダイアログにスタイル(テーマ)を適用するのにこの方法を用いている。基本的に Android システム以外からリソースID(int値)を利用することはわかりずらいので(アプリ固有の場合、ビルドでも変わるので)、動的に取得する方が適切だろう。なお、ID 取得に失敗したときは0になる(無い場合もエラーにはならない)。

●テーマ(スタイル)の ID(int)を取得する(関数定義)
import android.content.Context;

public static final int getStyleID(final Context context, final String name) {
if (name != null && name.length() > 0)
return context.getResources().getIdentifier(name, "style", context.getPackageName());
return 0; //取得失敗
}

●使用例(メインでのコードなど)
import android.util.Log;

//※アクティビティでの使用例
String holo_s = "android:Theme.Holo.Light.Dialog";
int holo_i = getStyleID(this, holo_s); //this は context
int holo_r = android.R.style.Theme_Holo_Light_Dialog;

String devDef_s = "android:Theme.DeviceDefault.Light.Dialog.Alert";
int devDef_i = getStyleID(this, devDef_s); //this は context
int devDef_r = android.R.style.Theme_DeviceDefault_Light_Dialog_Alert;

String mat_s = "android:Theme.Material.Light.Dialog.Alert";
int mat_i = getStyleID(this, mat_s); //this は context
int mat_r = android.R.style.Theme_Material_Light_Dialog_Alert;

Log.d("DebugTag", "holo_s = " + holo_s);
Log.d("DebugTag", "holo_i = " + holo_i);
Log.d("DebugTag", "holo_r = " + holo_r);
Log.d("DebugTag", "devDef_s = " + devDef_s);
Log.d("DebugTag", "devDef_i = " + devDef_i);
Log.d("DebugTag", "devDef_r = " + devDef_r);
Log.d("DebugTag", "mat_s = " + mat_s);
Log.d("DebugTag", "mat_i = " + mat_i);
Log.d("DebugTag", "mat_r = " + mat_r);

holo_s = android:Theme.Holo.Light.Dialog
holo_i = 16973939
holo_r = 16973939
devDef_s = android:Theme.DeviceDefault.Light.Dialog.Alert
devDef_i = 16974546
devDef_r = 16974546
mat_s = android:Theme.Material.Light.Dialog.Alert
mat_i = 16974394
mat_r = 16974394

 引数に与えてる文字列("_s" の付くもの)と Android システムの定数("_r" の付くもの)の名前を比較してみると、定数名:"android.R.style.Theme" → 文字列定数:"android:Theme" に置き換え、それ以降のアンダーバー("_")をドット(".")に置き換えれば相互変換できるとわかる。実際にはデベロッパーサイトの資料でもシステム固有値は掲載されているが、文字列から変換できると、ユーザー指定など色々便利である。特にアプリ固有の ID「(パッケージ名).R.~」の場合は、ビルドによって値が変わることもあるので、文字列から動的にIDを取得すれば、外部から利用したいときなども適切に処理できる。

(Android システムでの固有値)
Theme(テーマ[スタイル])



■リソースの種類を指定して ID(int値)を文字列から取得する

 内容的には「テーマ(スタイル)の ID(int値)取得」と同じなのだが、もう少し汎用的にリソースの種類を指定して ID(int値)を取得する関数を書いておこう。どちらかというとこっちが主役で「テーマ(スタイル)」などは種類別に書いておくと良いと思う。また文字列が空であるか否かを調べる関数も定義しておけば、かなりすっきりしたものになる。その例を挙げておこう。

●リソースの種類を指定して ID(int値)を取得する+空文字のチェック(関数定義)
import android.content.Context;

//リソースID(int値)を取得する
public static final int getResourceID(final Context context, final String type, final String name) {
if (!isNullOrEmpty(name) && !isNullOrEmpty(type))
return context.getResources().getIdentifier(name, type, context.getPackageName());
return 0; //取得失敗
}

//文字列が null または空のとき真を返す
public static final boolean isNullOrEmpty(final String str) {
return (str == null || str.length() == 0);
}

●使用例(メインでのコードなど)
import android.util.Log;

//※アクティビティでの使用例
int ic_lancher = R.mipmap.ic_launcher;
int ic_launcher_background = R.drawable.ic_launcher_background;

int app_name = R.string.app_name;
int mipmapID = getResourceID(this, "mipmap", "ic_launcher"); //this は context

int drawableID = getResourceID(this, "drawable", "ic_launcher_background"); //this は context
int stringID = getResourceID(this, "string", "app_name"); //this は context

Log.d("DebugTag", "ic_lancher = " + ic_lancher);
Log.d("DebugTag", "mipmapID = " + mipmapID);
Log.d("DebugTag", "ic_launcher_background = " + ic_launcher_background);
Log.d("DebugTag", "drawableID = " + drawableID);
Log.d("DebugTag", "app_name = " + app_name);
Log.d("DebugTag", "stringID = " + stringID);

ic_lancher = 2131361792
mipmapID = 2131361792
ic_launcher_background = 2131099732
drawableID = 2131099732
app_name = 2131427357
stringID = 2131427357

 ここでは例として "mipmap" や "drawable", "string" などを挙げているが、Android Studio を使っているなら、"R." を書いた後に出てくる入力補完に色々出てくるものが種類(ここでは引数の type)に相当すると考えて良いだろう。名前(name)は種類の "." 以降のものである。また Android システム自身が持っているリソースは "android:XXX~" と書けば良い(エディタ上で [Ctrl+B] を押せば参照できることがある[xml など])。


 以上の説明を踏まえて、前述した「テーマ(スタイル)の ID(int値)取得」や "mipmap", "drawable", "string" などを種類別に書いても良いだろう("string" の場合は "app_name" [アプリ名] などと組み合わせた関数を作ると楽かも知れない)。例えば以下のような関数を作っても良い。

●"mipmap", "drawable", "string" などのID(int値)を文字列から取得する
import android.content.Context;

//・・・(前述の関数定義は略)・・・

//テーマ(スタイル)のリソースIDを取得 [※種類別に書き換えた例]
public static final int getStyleID(final Context context, final String name) {
return getResourceID(context, "style", name);
}

//Mipmap画像("res/mipmap~")のリソースIDを取得(API 11)
public static final int getMipmapID(final Context context, final String name) {
return getResourceID(context, "mipmap", name); //API 11
}

//画像("res/drawable~")のリソースのIDを取得
public static final int getDrawableID(final Context context, final String name) {
return getResourceID(context, "drawable", name);
}

//文字列のリソースIDを取得
public static final int getStringID(final Context context, final String name) {
return getResourceID(context, "string", name);
}

//アプリ名のリソースIDを取得
public static final int getAppNameID(final Context context) {
return getResourceID(context, "string", "app_name"); //※デフォルトの場合
}

//アプリ名を取得
public static final String getAppName(final Context context) {
final int id = getAppNameID(context);
if (id != 0)
return context.getResources().getString(id);
return ""; //取得失敗。"app_name" 以外?(無いものもある)
}

 "string" 等の場合はIDから「String str = getResources().getString(stringID);」(アクティビティ上)のようにすれば文字列を取得することもできる。ただし、ID 取得に失敗したときは0になるので注意しよう(無い場合もエラーにはならない)。なお、デフォルトの場合 "app_name" にアプリ名が書かれたりするが(リソースの "res/values/string.xml")、アプリによっては書かれてないものもあるので気をつけて欲しい(そもそも xml を定義してないもの[サービスアプリとか]もある)。その場合は「PackageManager」からアプリ名を取得する方法もあるが、それはまた次の記事を見て欲しい。

 よく利用するものだけでも作っておけば便利なので、色々やってみると良いだろう。





(関連記事)
【Android】【Java】アプリ名、バージョン番号(versionCode)、バージョン名(versionName)などをコードで取得する(PackageManager を利用)
【Android】【Java】アプリ名 app_name タグをコードで取得する
【Android】【Java】画像リソースIDをコードで取得する
【Android】【Java】リソース名で、res/drawable-~ フォルダから、画像を読み込む(Bitmap)
【Android】【Java】リソース名で、res/drawable-~ フォルダから、画像を読み込む(Drawable)
【Android】【Java】res/raw リソースフォルダからテキストファイルを読み込む


category: Android

thread: プログラミング

janre: コンピュータ

tag: Androidライブラリ  Java 
tb: 0   cm: --


プロフィール

Social

検索フォーム

全記事一覧

カテゴリ

ユーザータグ

最新記事

リンク

PR

▲ Pagetop