จะตรวจสอบได้อย่างไรว่ามีการลงนาม APK หรือ "debug build"


121

เท่าที่ฉันรู้ใน Android "release build" มีการลงนาม APK จะตรวจสอบจากโค้ดได้อย่างไรหรือ Eclipse มีความลับบางอย่างกำหนดไว้หรือไม่?

ฉันต้องการสิ่งนี้เพื่อดีบักการเติมข้อมูลรายการ ListView จากข้อมูลบริการบนเว็บ (ไม่ใช่ logcat ไม่ใช่ตัวเลือก)

ความคิดของฉัน:

  • แอปพลิเคชันandroid:debuggableแต่ด้วยเหตุผลบางประการที่ดูไม่น่าเชื่อถือ
  • รหัสอุปกรณ์ฮาร์ดโค้ดไม่ใช่ความคิดที่ดีเพราะฉันใช้อุปกรณ์เดียวกันในการทดสอบ APK ที่ลงชื่อ
  • ใช้การตั้งค่าสถานะด้วยตนเองในรหัสหรือไม่? เป็นไปได้ แต่แน่นอนจะลืมที่จะเปลี่ยนแปลงในบางครั้งบวกกับโปรแกรมเมอร์ทุกคนขี้เกียจ

การแก้ไขของ Phil แบบย้อนกลับ นี่ไม่ใช่คำถามเกี่ยวกับการเผยแพร่โปรแกรมอย่างถูกกฎหมายในตลาดหรือไม่ คำถามเกี่ยวกับคือโปรแกรมยังอยู่ใน "โหมดดีบัก"
Im0rtality

วิธีนี้เป็นวิธีที่ง่ายที่สุด: stackoverflow.com/a/23844716/2296787
MBH

คำตอบ:


80

มีวิธีอื่นในการตรวจสอบว่าแอปพลิเคชันสร้างโดยใช้การดีบักหรือใบรับรองการเผยแพร่ แต่วิธีต่อไปนี้ดูเหมือนจะดีที่สุดสำหรับฉัน

ตามข้อมูลในเอกสาร Android การ ลงนามแอปพลิเคชันของคุณคีย์การแก้ไขข้อบกพร่องจะมีชื่อเฉพาะของหัวเรื่องต่อไปนี้: " 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.X509Certificate, และjava.security.cert.CertificateException android.content.pm.Signatureชั้นเรียนอื่น ๆ ทั้งหมดไม่ได้นำเสนอการแข่งขันหลายรายการสำหรับฉัน
Christian García

1
แก้ไขคำตอบด้วยการนำเข้าเหล่านี้ ขอบคุณ!
Cory Petosky

มีประสิทธิภาพเพียงพอที่จะรันบนเมธอด onCreate ของคลาสแอปพลิเคชันหรือไม่
นักพัฒนา Android

ฉันไม่ได้สังเกตเวลาดำเนินการ แต่ฉันใช้มันในแอพของฉันและไม่มีปัญหาใด ๆ กับประสิทธิภาพ
Omar Rehman

ผลลัพธ์สามารถแคชเพื่อประสิทธิภาพ
ftvs

138

ในการตรวจสอบแฟล็กที่แก้ไขได้คุณสามารถใช้รหัสนี้:

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

Kotlin:

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

สำหรับข้อมูลเพิ่มเติมโปรดดูที่การประยุกต์ใช้งานการรักษาความปลอดภัยของ Android LVL

หรือหากคุณใช้ Gradle อย่างถูกต้องคุณสามารถตรวจสอบได้ว่าBuildConfig.DEBUGจริงหรือเท็จ


ดูเหมือนว่าจะยังตรวจสอบ android ของรายการ: debuggable
xster

2
รายการแรกทดสอบ Manifest debuggable ซึ่งเลิกใช้แล้ว อันที่สองเป็นไปไม่ได้สำหรับไลบรารี lib จะมี BuildConfig ของตัวเอง - ไม่สามารถนำเข้า BuildConfig ของแอพซึ่งใช้ Lib ดังนั้นคำตอบที่ทำเครื่องหมายไว้คือ "ตกลง"
Christoph

คำตอบนี้ใช้ได้ในทุกกรณีไม่ว่าโครงการห้องสมุดหรือโครงการแอปพลิเคชัน
Lavekush Agrawal

131

ตอบโดย Mark Murphy

ที่ง่ายและดีที่สุดแก้ปัญหาระยะยาวBuildConfig.DEBUGคือการใช้งาน นี่คือbooleanค่าที่จะใช้trueสำหรับการสร้างดีบักfalseมิฉะนั้น:

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

8
ข้อเสียเปรียบเพียงประการเดียวของแนวทางนี้คือจะใช้ไม่ได้ในโครงการห้องสมุด (aar's) เมื่อสร้างไลบรารีแล้วสิ่งนี้จะส่งผลให้เป็นเท็จดังนั้นแม้ว่าแอปพลิเคชันที่ใช้ไลบรารีจะอยู่ในโหมดดีบักการตรวจสอบนี้จะส่งผลให้เป็นเท็จภายในรหัสไลบรารี
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

นี่คือคำตอบที่ดีที่สุด!
Peter Fortuin

ไม่ใช่ถ้าคุณกำลังเขียนไลบรารีของบุคคลที่สามและไม่ทราบแพ็คเกจของ BuildConfig ในเวลาคอมไพล์
Sam Dozor

แซมคุณช่วยอธิบายเรื่องนี้ได้ไหม?
Agamemnus

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 ของฉัน (เนื่องจากรหัสแอปพลิเคชันแตกต่างกัน)
Baz

5

มีการลงนามบิลด์การแก้ไขข้อบกพร่องเช่นกันโดยใช้คีย์อื่น Eclipse สร้างขึ้นโดยอัตโนมัติและใบรับรองมีอายุหนึ่งปีเท่านั้น มีปัญหา android:debuggableอะไร PackageManagerคุณจะได้รับความคุ้มค่าจากการใช้รหัส


3

อีกทางเลือกหนึ่งที่น่ากล่าวถึง หากคุณต้องการรันโค้ดบางโค้ดเมื่อติดดีบักเกอร์เท่านั้นให้ใช้รหัสนี้:

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

0

แก้ไขด้วยandroid:debuggable. มันเป็นข้อผิดพลาดในการอ่านรายการที่ในบางกรณีการแก้ปัญหาธงในรายการไม่ได้ถูกเก็บไว้ในบันทึกที่ได้รับการประเมินผลเสมอif (m.debug && !App.isDebuggable(getContext())) falseความผิดฉันเอง.


13
ฉันรู้ว่านี่อายุเกินหนึ่งปีแล้ว แต่คุณควรยอมรับคำตอบของ @Omar Rehman ไม่ใช่คำตอบนี้ แม้ว่าสิ่งที่คุณโพสต์จะเป็นสิ่งที่คุณทำในที่สุด แต่ก็ไม่ได้ตอบคำถามที่คุณถามอย่างแท้จริงในขณะที่โซลูชันของ Omar ดูเหมือนจะทำเช่นนั้นหมายความว่าเขาสมควรได้รับเครดิตที่ยอมรับ
mAh

7
@Mah - ไม่เหมาะสมอย่างยิ่งที่จะกลั่นแกล้งคนที่ไม่ยอมรับคำตอบที่โพสต์ไว้เกือบหนึ่งปีหลังจากที่พวกเขาแก้ไขปัญหาด้วยตัวเอง! และนั่นยังไม่สนใจว่าคำตอบที่คุณเสนอชื่อนั้นซับซ้อนกว่าคำตอบที่พวกเขาไปด้วย - ซึ่งในความเป็นจริงตอบคำถามที่ถามเนื่องจากคำถามได้รับแจ้งจากข้อผิดพลาดซึ่งนำไปสู่การแสดงผลที่ผิดพลาดว่าการตั้งค่าสถานะไม่น่าเชื่อถือ .
Chris Stratton

4
@ChrisStratton ถ้าคุณคิดว่าคำตอบของฉันเป็นการกลั่นแกล้งฉันคิดว่าคุณไม่อ่านอินเทอร์เน็ตมากนัก ฉันสนับสนุนสิทธิ์ของคุณในการโพสต์มุมมองที่เป็นปฏิปักษ์ของคุณในความคิดเห็นเช่นเดียวกับที่คุณทำและด้วยเหตุนี้ฉันจึงได้ตรวจสอบความคิดเห็นของฉันและโพสต์อื่น ๆ ในคำถามนี้และฉันก็ยืนตามความคิดเห็นเดิมของฉัน: ผู้โพสต์ถามคำถามที่ถูกต้องตามกฎหมาย และมีคนตอบอย่างถูกต้อง จาก "คำตอบ" ของเขาเองคำถามเดิมของเขาไม่ใช่สิ่งที่เขาต้องการถามตั้งแต่แรก ... ลายเซ็นของ APK (รุ่นหรือการแก้ไขข้อบกพร่อง) มีผลกับไฟล์ Manifest เป็นศูนย์
mAh

3
@mah - ขึ้นอยู่กับผู้ถามไม่ใช่คุณจะตัดสินใจว่าสิ่งใดที่ตอบสนองความต้องการในการใช้งานจริงของพวกเขารวมถึงความแตกต่างที่คุณยกให้เป็นสิ่งสำคัญหรือไม่อย่างที่เห็นได้ชัดในกรณีนี้ไม่ใช่ ที่สำคัญคุณมองข้ามไปโดยสิ้นเชิงว่าคำตอบที่คุณเสนอชื่อถูกโพสต์เกือบหนึ่งปีหลังจากที่พวกเขาตอบสนองความต้องการที่แท้จริง เป็นการลงโทษใครบางคนที่ไม่กลับมาเปลี่ยนการยอมรับเกือบหนึ่งปีต่อมาซึ่งถือเป็นการกลั่นแกล้ง
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.