Android 如何检查APK是否已签名或;调试生成“;?

Android 如何检查APK是否已签名或;调试生成“;?,android,debugging,certificate,Android,Debugging,Certificate,据我所知,在安卓系统中,“发布版本”的签名是APK。如何从代码中检查它,或者Eclipse是否有某种秘密定义 我需要它来调试从web服务数据填充ListView项(否,logcat不是选项) 我的想法: 应用程序的android:debugable,但由于某些原因,它看起来不可靠 硬编码设备ID不是个好主意,因为我正在使用同一个设备测试签名的APK 在代码中的某个地方使用手动标志?这是有道理的,但肯定会忘记在某个时候进行更改,再加上所有的程序员都很懒 调试版本也会被签名,只是使用了不同的密钥。

据我所知,在安卓系统中,“发布版本”的签名是APK。如何从代码中检查它,或者Eclipse是否有某种秘密定义

我需要它来调试从web服务数据填充ListView项(否,logcat不是选项)

我的想法:

  • 应用程序的
    android:debugable
    ,但由于某些原因,它看起来不可靠
  • 硬编码设备ID不是个好主意,因为我正在使用同一个设备测试签名的APK
  • 在代码中的某个地方使用手动标志?这是有道理的,但肯定会忘记在某个时候进行更改,再加上所有的程序员都很懒

    • 调试版本也会被签名,只是使用了不同的密钥。它是由Eclipse自动生成的,其证书的有效期仅为一年。android:debugable有什么问题?您可以使用
      PackageManager

      从代码中获取此值要检查可调试标志,您可以使用以下代码:

      boolean isDebuggable =  ( 0 != ( getApplicationInfo().flags & ApplicationInfo.FLAG_DEBUGGABLE ) );
      
      if (Debug.isDebuggerConnected() || Debug.waitingForDebugger()) { 
          //code to be executed 
      }
      
      科特林:

      val isDebuggable = 0 != applicationInfo.flags and ApplicationInfo.FLAG_DEBUGGABLE
      
      有关更多信息,请参阅


      或者,如果正确使用Gradle,可以检查
      BuildConfig.DEBUG
      是否正确。

      使用
      android:debugable
      解决。读取项时出现错误,在某些情况下,项上的调试标志未存储在记录get
      if(m.debug&&!App.isDebuggable(getContext())
      中,始终计算为
      false
      。我的错。

      有不同的方法来检查应用程序是使用调试证书还是发布证书构建的,但以下方法对我来说似乎是最好的

      根据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;
      }
      
      private static final X500Principal DEBUG_DN=new X500Principal(“CN=Android DEBUG,O=Android,C=US”);
      专用布尔值isDebuggable(上下文ctx)
      {
      布尔可调试=假;
      尝试
      {
      PackageInfo pinfo=ctx.getPackageManager().getPackageInfo(ctx.getPackageName(),PackageManager.GET_签名);
      签名[]=pinfo.signatures;
      CertificateFactory cf=CertificateFactory.getInstance(“X.509”);
      对于(int i=0;i
      可能很晚,但是iosched使用了
      BuildConfig.DEBUG
      如果您想静态检查
      APK
      ,您可以使用

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

      如果APK不可调试,则输出
      0
      ;如果可调试,则输出
      1

      另一个值得一提的选项。如果仅在附加调试器时才需要执行某些代码,请使用以下代码:

      boolean isDebuggable =  ( 0 != ( getApplicationInfo().flags & ApplicationInfo.FLAG_DEBUGGABLE ) );
      
      if (Debug.isDebuggerConnected() || Debug.waitingForDebugger()) { 
          //code to be executed 
      }
      

      马克·墨菲回答

      最简单也是最好的长期解决方案是使用
      BuildConfig.DEBUG
      。这是一个
      boolean
      值,对于调试生成,
      false
      否则:

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

      首先将其添加到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;
          }
      }
      

      我目前使用的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过程)

      回滚Phil的编辑。这并不是节目是否在市场上合法发行的问题。问题是程序是否仍然处于“调试模式”。这种方式是最简单的方式:我知道这已经超过一年了,但你们应该接受@Omar Rehman的答案,而不是这个。虽然你所发布的内容是你最终所做的,但它并不能真正回答你提出的问题,而奥马尔的解决方案似乎能做到这一点,这意味着他应该得到公认的荣誉。@Mah-欺负一个人,因为他不接受他们自己解决问题将近一年后发布的答案,这是完全不合适的!这甚至忽略了你所推荐的答案比他们给出的答案要复杂得多——事实上,这回答了问题,因为问题是由一个错误引起的,导致错误的印象,即国旗不可靠。@ChrisStratton如果你认为我的回答是欺凌,我想你不怎么上网。我支持你在评论中发表反对观点的权利,正如你所做的那样,因此我已经回顾了我的评论和这个问题中的其他帖子,我支持我最初的评论:海报提出了一个问题,这个问题得到了某人的合理和正确的回答。根据他自己的“答案”,他最初的问题不是他想问的。。。APK的签名(发布或调试)对清单的影响完全为零。@mah-由询问者而不是你来决定什么满足了他们的实际应用需要,包括你提出的区别是否重要,或者,在本例中,显然不是。更重要的是,你完全忽略了你所提名的答案是在他们的实际需求得到满足将近一年后发布的。这是对一个人的惩罚,因为他在一年后的大部分时间里都没有回来改变自己的接受,这就构成了欺凌。@ChrisStratton提问者还应该问他/她想要答案的实际问题——有些事情是