APKが署名されているか、または「デバッグビルド」されているかどうかを確認するにはどうすればよいですか?


121

私の知る限り、Androidでは「リリースビルド」にAPKが署名されています。コードからそれをチェックする方法、またはEclipseには何らかの秘密の定義がありますか?

WebサービスデータからのListViewアイテムの生成をデバッグするためにこれが必要です(いいえ、logcatはオプションではありません)。

私の考え:

  • アプリケーションのものandroid:debuggableですが、何らかの理由で信頼できません。
  • 署名付きAPKのテストに同じデバイスを使用しているため、デバイスIDをハードコーディングすることはお勧めできません。
  • コードのどこかに手動フラグを使用していますか?もっともですが、いつか変更することを間違いなく忘れるだけでなく、すべてのプログラマーは怠惰です。

Philの編集をロールバック。これは、プログラムが合法的に市場に配布されているかどうかの問題ではありません。それはまだ「デバッグモード」のプログラムであるかどうかについての質問です。
Im0rtality 2011

この方法が最も簡単な方法です:stackoverflow.com/a/23844716/2296787
MBH

回答:


80

アプリケーションがデバッグ証明書またはリリース証明書を使用してビルドされているかどうかを確認する方法はいくつかありますが、私には次の方法が最善のようです。

AndroidドキュメントのSigning Your Applicationの情報によると 、デバッグキーには次のサブジェクト識別名が含まれています: " CN = Android Debug、O = Android、C = US "。この情報を使用して、デバッグキーの署名をコードにハードコーディングせずに、パッケージがデバッグキーで署名されているかどうかをテストできます。

与えられた:

import android.content.pm.Signature;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;

次の方法でisDebuggableメソッドを実装できます。

private static final X500Principal DEBUG_DN = new X500Principal("CN=Android Debug,O=Android,C=US");
private boolean isDebuggable(Context ctx)
{
    boolean debuggable = false;

    try
    {
        PackageInfo pinfo = ctx.getPackageManager().getPackageInfo(ctx.getPackageName(),PackageManager.GET_SIGNATURES);
        Signature signatures[] = pinfo.signatures;

        CertificateFactory cf = CertificateFactory.getInstance("X.509");

        for ( int i = 0; i < signatures.length;i++)
        {   
            ByteArrayInputStream stream = new ByteArrayInputStream(signatures[i].toByteArray());
            X509Certificate cert = (X509Certificate) cf.generateCertificate(stream);       
            debuggable = cert.getSubjectX500Principal().equals(DEBUG_DN);
            if (debuggable)
                break;
        }
    }
    catch (NameNotFoundException e)
    {
        //debuggable variable will remain false
    }
    catch (CertificateException e)
    {
        //debuggable variable will remain false
    }
    return debuggable;
}

6
複数のインポートマッチングの解決を支援するために、ここで使用されるクラスはjava.security.cert.X509Certificatejava.security.cert.CertificateExceptionおよびandroid.content.pm.Signatureです。他のすべてのクラスでは、私に複数の試合はありません
ChristianGarcía'29

1
これらのインポートでの回答の編集。ありがとう!
Cory Petosky 2013

アプリケーションクラスのonCreateメソッドで実行するのに十分効率的ですか?
Android開発者

実行時間は記録していませんが、アプリで使用しており、効率に問題はありません。
Omar Rehman 2013年

結果は効率のためにキャッシュすることができます。
ftvs 2014

138

デバッグ可能なフラグを確認するには、次のコードを使用できます。

boolean isDebuggable =  ( 0 != ( getApplicationInfo().flags & ApplicationInfo.FLAG_DEBUGGABLE ) );

コトリン:

val isDebuggable = 0 != applicationInfo.flags and ApplicationInfo.FLAG_DEBUGGABLE

詳細については、Android LVLアプリケーションの保護をご覧ください。

または、Gradleを正しく使用している場合BuildConfig.DEBUGは、trueかfalse かを確認できます。


これはまだマニフェストのandroid:
debuggableを

2
最初のものはデバッグ可能なマニフェストをテストしますが、これは非推奨です。2つ目はライブラリでは不可能です。ライブラリには独自のBuildConfigがあります。Libを使用しているアプリのBuildConfigをインポートできません。そのため、マークされた答えは「大丈夫」
クリストフ

この回答は、ライブラリプロジェクトやアプリケーションプロジェクトに関係なく、すべてのケースで機能します。
Lavekush Agrawal 2017

131

マーク・マーフィーが答えました

最も簡単で長期的な解決策は、を使用することBuildConfig.DEBUGです。これは、デバッグビルド用のboolean値ですtruefalseそれ以外の場合:

if (BuildConfig.DEBUG) {
  // do something for a debug build
}

8
このアプローチの唯一の欠点は、ライブラリプロジェクト(aar's)では機能しないことです。ライブラリがビルドされると、これはfalseになります。そのため、ライブラリを使用するアプリケーションがデバッグモードであっても、このチェックはライブラリコード内でfalseになります。
Vito Andolini

24

APK静的にチェックしたい場合は、

aapt dump badging /path/to/apk | grep -c application-debuggable

この出力0場合APKデバッグではなく、1それがある場合。


3
これは、最終的なAPKで検証する唯一のソリューションです。他の応答は、ソースがあることを前提としています。
Guillermo Tobar

1
aaptここに住んでいます/Users/USER_NAME/library/Android/sdk/build-tools/28.0.3/aapt
Casey

21

多分遅いですが、ioschedは BuildConfig.DEBUG


安全に使用できますか?いくつかの問題があると言っている記事があります:digipom.com/be-careful-with-buildconfig-debug
android developer

これが一番の答えです!
Peter Fortuin、2014年

サードパーティのライブラリを作成していて、コンパイル時にBuildConfigのパッケージがわからない場合はそうではありません。
Sam Dozor 2014

サム、これについて詳しく説明してもらえますか?
アガメムス2015年

10

まず、これをbuild.gradleファイルに追加します。これにより、デバッグビルドとリリースビルドの並行実行も可能になります。

buildTypes {
    debug {
        applicationIdSuffix ".debug"
    }
}

このメソッドを追加します。

public static boolean isDebug(Context context) {
    String pName = context.getPackageName();
    if (pName != null && pName.endsWith(".debug")) {
        return true;
    } else {
        return false;
    }
}

1
信頼できるからです。ただし、新しい「許可されたAndroidアプリケーション」エントリをGoogle Maps APIキーに追加する必要がありました(アプリケーションIDが異なるため)。
Baz

5

デバッグビルドも、別のキーで署名されています。Eclipseによって自動的に生成され、その証明書は1年間のみ有効です。何が問題なの android:debuggableですか?この値は、を使用してコードから取得できますPackageManager


3

言及する価値のある別のオプション。デバッガーがアタッチされているときにのみいくつかのコードを実行する必要がある場合は、次のコードを使用します。

if (Debug.isDebuggerConnected() || Debug.waitingForDebugger()) { 
    //code to be executed 
}

0

で解決android:debuggable。アイテムのデバッグフラグがif (m.debug && !App.isDebuggable(getContext()))常に評価されるレコードに格納されていない場合があるのは、アイテムの読み取りのバグでしたfalse。私の悪い。


13
これは1年以上前のものだと思いますが、@ Omar Rehmanの答えではなく、これを受け入れるべきでした。あなたが投稿したのは最終的にあなたがしたことですが、それはあなたが尋ねた質問に実際に答えることはありませんが、オマーのソリューションはそれをするように見えます、つまり彼は受け入れられた信用に値します。
MAH

7
@Mah-誰かが自分で問題を解決してからほぼ1年後に投稿された回答を受け入れなかったとして、いじめを行うことはまったく不適切です。 そして、それはあなたが指名した答えが彼らが行ったものよりもはるかに複雑であることを無視しています-フラグは信頼できないという誤った印象につながるバグによって質問が促されたので、実際には質問に答えます。
Chris Stratton、

4
@ChrisStrattonもし私の返答がいじめだと思ったら、インターネットをあまり読んでいないと思います。私はあなたがそうであったようにコメントであなたの反対の視点を投稿するあなたの権利を支持します、そしてその結果、私はこの質問の私のコメントと他の投稿をレビューしました、そして私は私の元のコメントを待ちます:ポスターは合法的な質問をしましたそして誰かが正しく答えました。彼自身の「答え」に基づいて、彼の元の質問はそもそも彼が尋ねたかったものではありません... APKの署名(リリースまたはデバッグ)は、マニフェストにまったく関係がありません。
MAH

3
@mah- あなたが上げる区別が重要なものであるかどうかを含めて、実際のアプリケーションのニーズを満たすものを決めるのはあなたの質問次第です。この場合は明らかに、そうではありません。さらに重要なのは、指名した回答が、実際のニーズが満たされてからほぼ1年後に投稿されたことを完全に見落としていることです。いじめを構成する1年のほとんど後に彼らの受け入れを変更するために戻ってこないために誰かを罰しています。
Chris Stratton、

3
@ChrisStrattonまた、彼/それが答えを望んでいる実際の質問をするのは質問者次第です-この場合、行われなかった何か。投稿された内容に実際に答えている答えが出たときに見落としていたのは正しいですが、罰はまったくなく、私の意見は合理的にしか表現されていません。私がここでいじめっ子を演じていると思われる場合は、私のコメントに不正行為を報告するよう強く要請してください。ただし、その前に、自分の投稿をここで確認することをお勧めします。
mah

0

現在使用しているKotlinのソリューション:

@SuppressLint("PackageManagerGetSignatures")
@Suppress("DEPRECATION")
fun isSigned(context: Context?): Boolean {
    return (context?.packageManager?.getPackageInfo(context.packageName, PackageManager.GET_SIGNATURES)?.signatures?.firstOrNull()?.toByteArray()
            ?.let {
                return@let CertificateFactory.getInstance("X.509").generateCertificate(ByteArrayInputStream(it))
            } as? X509Certificate)
            ?.issuerDN
            ?.name
            ?.contains("O=Android", ignoreCase = false) ?: true
}

そうすれば、デバッグで署名することができ、それらはCrashlyticsに報告されます(例、QAプロセスの場合)

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.