デバッグか否かを決める方法について

601 views
Skip to first unread message

Shigeo Mutoh

unread,
Jun 30, 2014, 3:54:46 AM6/30/14
to android-g...@googlegroups.com
武藤です。

急ぎということはないのですが、前から気になってたので質問させて
ください。

AndroidManifest.xmlのapplicationに、android:debuggable属性
を書かないことを推奨されて久しいですが、アプリケーション内から
自分自身がデバッグなのかリリースなのかを知る良い方法はどのような
ものになるでしょうか?

できれば、自分自身の.apkの署名情報を取り出せれば一番確実なのでは
ないかと思っているのですが、その方法がわかっていません。
それが分かると、mapなどで必要なapi keyをデバッグとリリースで自動
振り分けできるので便利です。

以下参考までに、以前書いた「ダメなコード」です。
よろしくお願いします。

1 /**
2 * パッケージがdebuggerble=trueか否か.
3 * @param context
4 * @return
5 */
6 public static boolean isDebuggable(Context context) {
7 if( s_isDebug == null ) {
8 s_isDebug = false;
9 try {
10 PackageManager manager = context.getPackageManager();
11 ApplicationInfo appInfo = manager.getApplicationInfo(
12 context.getPackageName(), 0);
13 if ((appInfo.flags & ApplicationInfo.FLAG_DEBUGGABLE) ==
14 ApplicationInfo.FLAG_DEBUGGABLE) {
15 s_isDebug = true;
16 }
17 } catch (NameNotFoundException e) {
18 }
19 }
20 return(s_isDebug);
21 }

awwa

unread,
Jun 30, 2014, 4:07:05 AM6/30/14
to android-g...@googlegroups.com
武藤さん
あわともうします。

妥当な方法かわかりませんが、私の場合はこんな感じで署名を取って判断していました。



PackageManager pm = context.getPackageManager();

PackageInfo pi2 = null;

pi2 = pm.getPackageInfo(packageName, PackageManager.GET_SIGNATURES);

if ( (pi2 != null) && (pi2.signatures.length > 0))

{

    signature = pi2.signatures[0].toCharsString();

}


昔々試行錯誤しつつ書いたコードでその後検証とかしていませんので、もっとちゃんとしたやり方があるのかもしれませんが。

ではでは




2014年6月30日 16:54 Shigeo Mutoh <tmh...@gmail.com>:

--
このメールは Google グループのグループ「日本Androidの会」の登録者に送られています。
このグループから退会し、グループからのメールの配信を停止するには android-group-j...@googlegroups.com にメールを送信してください。
このグループに投稿するには、android-g...@googlegroups.com にメールを送信してください。
http://groups.google.com/group/android-group-japan からこのグループにアクセスしてください。
その他のオプションについては、https://groups.google.com/d/optout にアクセスしてください。



--
awwa <aww...@gmail.com>
Twitter http://twitter.com/awwa500
Blog http://awwa500.blogspot.com/

さわださとし

unread,
Jun 30, 2014, 4:16:10 AM6/30/14
to android-g...@googlegroups.com
さわだです。

ADT17以降ではBuildConfig.java が自動生成されます。
この中の BuildConfig.DEBUG で判断できます。

public final static boolean DEBUG = true;

この値はリリースビルドを生成するときに自動的に false になるようです。

if (BuildConfig.DEBUG) {
// デバッグの処理
} else {
// リリースの処理
> --
> このメールは Google グループのグループ「日本Androidの会」の登録者に送られています。
> このグループから退会し、グループからのメールの配信を停止するには android-group-j...@googlegroups.com にメールを送信してください。
> このグループに投稿するには、android-g...@googlegroups.com にメールを送信してください。
> http://groups.google.com/group/android-group-japan からこのグループにアクセスしてください。
> その他のオプションについては、https://groups.google.com/d/optout にアクセスしてください。



--
さわださとし
http://www.satoshis.com/

Shigeo Mutoh

unread,
Jun 30, 2014, 4:30:41 AM6/30/14
to android-g...@googlegroups.com
武藤です。

awwaさん、ありがとうございます。やってみました。

signatureのバイト列が取れました。素晴らしいです。
中を覗くと78byte目あたりに'Android Debug'の文字が見れました。
あとはsignatureのフォーマットを調べたらなんとかなりそうです。

本当はroot CAがどうなっているかで判断するのが良いのでしょう。

素早いお返事をありがとうございました。

Shigeo Mutoh

unread,
Jun 30, 2014, 5:13:20 AM6/30/14
to android-g...@googlegroups.com
武藤です。

BuildConfig.DEBUGは、windows環境では役に立たないという情報
があって無視していました。
しかし今試してみると問題ありませんでした。(antによるrelease
apkの生成)

signatureを調べるのはナンセンスそうです。。

awwaさん、さわださん、ありがとうございました。

Shin Miyazaki

unread,
Jun 30, 2014, 6:49:38 AM6/30/14
to android-g...@googlegroups.com
こんばんは、みやざきです。

武藤さんの提示された「ダメなコード」はどこがダメなのか教えていただけますか?
私の作成したアプリでもデバッグモードでのみToastを表示するような処理を入れているのですが、判定についてはそのダメなコードと同様になっており、このままで大丈夫なのか非常に心配になってしまいました。


2014年6月30日 16:54 Shigeo Mutoh <tmh...@gmail.com>:
武藤です。

Shigeo Mutoh

unread,
Jun 30, 2014, 8:48:13 AM6/30/14
to android-g...@googlegroups.com
武藤です。

(14/6/30 19:49), Shin Miyazaki wrote:
> 武藤さんの提示された「ダメなコード」はどこがダメなのか教えていただけますか?

PackageManager::getApplicationInfo()が返すクラスである、
android.content.pm.ApplicationInfo
は以下のように定義されています。

Information you can retrieve about a particular application. This corresponds to
information collected from the AndroidManifest.xml's <application> tag.

なので、最近推奨されているようにandroid:debuggableをmanifestに
定義して「いなかった」場合、先のダメなコードは常にfalseを返す
ため役割を果たせなくなります。

ただし、推奨など知ったこっちゃない場合、つまりandroid:debuggable
属性が記述されていて、Debug版とRelease版とでtrue/falseが同期している
保証がある場合、isDebuggable()はその役目をきちんと果たすと思います。
誰かが余計なお世話さえしなければ。

たぶん、isDebuggableという名前が悪くて、
boolean getApplicationDebuggableAttributeValue()
とかにした方が良いのだと思います。これなら「デバッグか」という
抽象的な問いではなくて、manifestのdebuggable属性値を取ってこい
ということになり、名が体を表します。そして、デバッグか否かを
それで知ることはできないことが想像できます。

では。

Shigeo Mutoh

unread,
Jun 30, 2014, 10:14:55 AM6/30/14
to android-g...@googlegroups.com
武藤です。

後日談です。

最新型isDebugBuild()は汎用的に使えるからライブラリに
入れておこう、などとすると、ハマります。ハマりました。

BuildConfigはgenに生成されるただのクラスであり、同じ名前の
クラスが別のパッケージにも存在することを知らないとなりません。

なので、ライブラリで、
if( BuildConfig.DEBUG ) {
// 俺はデバッグ版だー。(たしかにそーだが、そーではない!)
}

は、何をimportするかによりますが、通常はこのライブラリの
BuildConfigを見ていることになり、危険です。

なので、アプリのBuildConfigを見るメソッドをライブラリに定義
するには、以下のような感じで実装しなければなりません。

1 public static boolean isDebugBuild(Context ctx) {
2 boolean isDebug = false;
3 try {
4 String packageName = ctx.getPackageName();
5 Class c = ctx.getClassLoader().loadClass(packageName +
".BuildConfig");
6 Field f = c.getDeclaredField("DEBUG");
7 isDebug = f.getBoolean(null);
8 } catch(いっぱい) {
9 throw new ありえねー無理っす();
10 }
11 return(isDebug);
12 }

こうすれば、Contextは必ずアプリから渡されるものなので、
ライブラリ内でもアプリがDebug版か否かを取得でき、正しく処理を
行えるはず、です。

では。

Shin Miyazaki

unread,
Jun 30, 2014, 10:43:32 PM6/30/14
to android-g...@googlegroups.com
返答ありがとうございます、みやざきです。

定義としては「AndroidManifest.xmlに指定されている値が反映されている」なのに、実際にはAndroidManifest.xmlにはそんなもの記述してはいるわけではない、というところが勘所でしょうか。
たしかにBuildConfig.DEBUGの方が感覚的にも見る場所としてはあっている気がしますね。

2014年6月30日 21:47 Shigeo Mutoh <tmh...@gmail.com>:
android-group-japan+unsub...@googlegroups.com にメールを送信してください。
このグループに投稿するには、android-group-ja...@googlegroups.com にメールを送信してください。

http://groups.google.com/group/android-group-japan からこのグループにアクセスしてください。
その他のオプションについては、https://groups.google.com/d/optout にアクセスしてください。

--
このメールは Google グループのグループ「日本Androidの会」の登録者に送られています。
このグループから退会し、グループからのメールの配信を停止するには android-group-japan+unsub...@googlegroups.com にメールを送信してください。
このグループに投稿するには、android-group-ja...@googlegroups.com にメールを送信してください。

Shigeo Mutoh

unread,
Jul 1, 2014, 4:00:20 AM7/1/14
to android-g...@googlegroups.com
武藤です。

皆さん、しつこくてすみません。。

デバッグ版か否かを知るのとほとんど同義だとは思うのですが、
自己署名されたapkか否かを知る方法を調べてみました。

これは、mapなどで必要になる各種api keyがapkの署名ファイルによって
異なることに自動対応したいという本来の目的のために、本来必要な
メソッドとして用意したものです。(本当の本当は、どの署名なのかを
特定すべきですが、さすがにそこまでは必要なかろうと。。)

もちろん、BuildConfig.DEBUGでも大抵は問題ないと思います。が、先に
述べましたように、ライブラリに引っ越しなどすると、とたんにトラブル
の元になりますので、BuildConfig.DEBUGを直に参照するのはあまり良い
習慣ではないと自分は思っています。というか自分はしません。

では。

327 /**
328 * 自己署名されたapkか.
329 * @param ctx
330 * @return
331 */
332 public static boolean isSelfSignedApk(Context ctx) {
333 boolean isDebug = false;
334 try {
335 PackageManager pm = ctx.getPackageManager();
336 String packageName = ctx.getPackageName();
337 PackageInfo pi = pm.getPackageInfo(packageName,
PackageManager.GET_SIGNATURES);
338
339 Signature sig = pi.signatures[0];
340 final byte[] sigBytes = sig.toByteArray();
341 InputStream certStream = new ByteArrayInputStream(sigBytes);
342
343 CertificateFactory cf = CertificateFactory.getInstance("X509");
344 X509Certificate x509 =
(X509Certificate)cf.generateCertificate(certStream);
345
346 //Principal p = x509.getSubjectDN();
347 //TmLog.d("principal getName = " + p.getName());
348 if( isSelfSigned(x509) ) {
349 isDebug = true;
350 }
351 } catch (Exception e) {
352 e.printStackTrace();
353 throw new RuntimeException("could not get signature.");
354 }
355 return(isDebug);
356 }
357
358 /**
359 * Checks whether given X.509 certificate is self-signed.
360 * from
http://www.nakov.com/blog/2009/12/01/x509-certificate-validation-in-java-build-and-verify-chain
-and-verify-clr-with-bouncy-castle/
361 */
362 public static boolean isSelfSigned(X509Certificate cert)
363 throws CertificateException, NoSuchAlgorithmException,
364 NoSuchProviderException {
365 try {
366 // Try to verify certificate signature with its own public key
367 PublicKey key = cert.getPublicKey();
368 cert.verify(key);
369 return true;
370 } catch (SignatureException sigEx) {
371 // Invalid signature --> not self-signed
372 return false;
373 } catch (InvalidKeyException keyEx) {
374 // Invalid key --> not self-signed
375 return false;
376 }
377 }

さとう

unread,
Jul 1, 2014, 8:08:48 AM7/1/14
to android-g...@googlegroups.com
横から失礼します、さとうと申します。

武藤さんのコードを動かしてみましたが、デバッグ版もリリース版もtrueが返ってきました。
私の場合、リリース用の証明書も自己署名証明書、いわゆるオレオレ証明書なので仕方がないですが。
皆さんはリリース用の証明書を、自分でCAを立てたり、どこかのCAを利用したりして発行しているんでしょうか?
//


2014年7月1日 16:59 Shigeo Mutoh <tmh...@gmail.com>:

Shigeo Mutoh

unread,
Jul 1, 2014, 9:42:36 AM7/1/14
to android-g...@googlegroups.com
武藤です。

(2014/07/01 21:08), さとう wrote:
> 横から失礼します、さとうと申します。

いえいえ。ありがとうございます。

> 武藤さんのコードを動かしてみましたが、デバッグ版もリリース版もtrueが返ってきました。

あれれ、試して成功したはずなのに。。
リリース用証明書(.keystore)って、googleから配られたやつで、オレオレ
ではないと信じてたのですが、そこからして私は間違ってましたということ??

詳しい人おしえてくださいませ。

では。

Makoto Yamazaki

unread,
Jul 1, 2014, 9:58:15 AM7/1/14
to android-g...@googlegroups.com
zaki です。

Android リリース用証明書は自分で適当に作るオレオレです。
アプリバージョンアップやアプリ連携の際には、同じ証明書であるということにしか
意味が無いので CA による署名は不要という判断なのだと思います。


--
このメールは Google グループのグループ「日本Androidの会」の登録者に送られています。
このグループから退会し、グループからのメールの配信を停止するには android-group-j...@googlegroups.com にメールを送信してください。
このグループに投稿するには、android-g...@googlegroups.com にメールを送信してください。
http://groups.google.com/group/android-group-japan からこのグループにアクセスしてください。
その他のオプションについては、https://groups.google.com/d/optout にアクセスしてください。



--
YAMAZAKI Makoto

Shigeo Mutoh

unread,
Jul 1, 2014, 10:56:46 AM7/1/14
to android-g...@googlegroups.com
武藤です。

zakiさん、ステキな情報を毎度ありがとうございます。
私の思い込み&テスト誤りで散らかしてしまってすみません。。

デバッグ用署名の場合、Principal::getName()で、"CN=Android Debug"
という文字列が取れたので、それで判断するのが適切だったのかも
しれません。

ごめんさない。
では。

さとう

unread,
Jul 2, 2014, 9:22:34 AM7/2/14
to android-g...@googlegroups.com
さとうです。

zaki さん、情報有り難うございます。
私だけオレオレ使っているのか? と少し心配になっていたので、そうではないと分かって安心しました。

武藤さん、
証明書の識別なら、証明書のハッシュ値を使うという手もありますね。もっとも、コード中にハッシュ値をベタ書きする必要がありますが。
//



2014年7月1日 23:56 Shigeo Mutoh <tmh...@gmail.com>:

Shigeo Mutoh

unread,
Jul 2, 2014, 11:58:09 AM7/2/14
to android-g...@googlegroups.com
武藤です。

さとうさん、そうですね、keystoreを特定する方法としてはhash値でいけると
一番最初に思いました。ただ、何かと使いにくいかなあと思い、オレオレか否か
で判定しようと思ったわけですが、失敗の巻でした。

では。
Reply all
Reply to author
Forward
0 new messages