2011-05-25 92 views
13

正如我們所做的那樣,我有一個應用程序,它在debug模式下(build)時由debug.keystore(默認)簽名。當它生產時,我們用我們的私鑰簽名。 有什麼方法可以在運行時確定當前軟件包是使用debug.keystore簽名的(處於開發模式)還是使用我們的私鑰簽名(處於生產模式)。Android將當前包的簽名與debug.keystore進行比較

我已經試過類似

PackageManager packageManager = getPackageManager(); 
    try { 
     Signature[] signs = packageManager.getPackageInfo(getPackageName(), PackageManager.GET_SIGNATURES).signatures; 
     for (Signature signature : signs) { 
      Log.d(TAG, "sign = " + signature.toCharsString()); 
     } 
    } catch (NameNotFoundException e) { 
     e.printStackTrace(); 
    } 

我不知道下一步該怎麼做?這是正確的方式嗎?如何獲得可比較的debug.keystore簽名?

我知道存在MD5指紋keytool -list -keystore ~/.android/debug.keystore但在Signature類中沒有「md5指紋」類似的方法。 我想這樣做是因爲MapView Key,Logging,LicenseChecker和類似的東西。

+0

現在,我使用1個靜態布爾值,每次執行產品發佈時都必須更改這些值。發生了,我忘了。 :( – zmeda 2011-05-25 10:13:22

回答

15

PackageInfo中的簽名似乎沒有明確命名,因爲該字段不包含軟件包簽名,而是簽名者X509證書鏈。請注意(大多數情況下)此鏈似乎僅限於一個自簽名證書。

根據Signing Your Applications這個DN生成調試簽名證書的Android開發者頁面:CN=Android Debug,O=Android,C=US

因此很容易測試應用程序已經在調試模式下籤訂:

private static final X500Principal DEBUG_DN = new X500Principal("CN=Android Debug,O=Android,C=US"); 
/* ... */ 
Signature raw = packageManager.getPackageInfo(getPackageName(), PackageManager.GET_SIGNATURES).signatures[0]; 
CertificateFactory cf = CertificateFactory.getInstance("X.509"); 
X509Certificate cert = (X509Certificate) cf.generateCertificate(new ByteArrayInputStream(raw.toByteArray())); 
boolean debug = cert.getSubjectX500Principal().equals(DEBUG_DN); 
+0

我假設'DEBUG_DN'是'X509Principal'類型的對嗎? – zmeda 2011-06-02 07:30:57

+0

DEBUG_DN是'X500Principal'類型,它是X.500名稱的容器 – Jcs 2011-06-24 11:31:09

+0

是否足夠高效地運行onCreate應用程序類? – 2013-07-25 12:05:30

3

基礎的在Jcs' answer上,我們使用這個在運行時找出構建運行包的人:

private enum BuildSigner { 
    unknown, 
    Joe, 
    Carl, 
    Linda 
} 

private BuildSigner whoBuiltThis() { 
    try { 
     PackageManager packageManager = getPackageManager(); 
     PackageInfo info = packageManager.getPackageInfo(getPackageName(), 
       PackageManager.GET_SIGNATURES); 
     Signature[] signs = info.signatures; 
     CertificateFactory cf = CertificateFactory.getInstance("X.509"); 
     X509Certificate cert = (X509Certificate)cf.generateCertificate(
       new ByteArrayInputStream(signs[0].toByteArray())); 
     PublicKey key = cert.getPublicKey(); 
     int modulusHash = ((RSAPublicKey)key).getModulus().hashCode(); 
     switch (modulusHash) { 
      case 123456789: 
       return BuildSigner.Joe; 
      case 424242424: 
       return BuildSigner.Carl; 
      case -975318462: 
       return BuildSigner.Linda; 
     } 
    } catch (Exception e) { 
    } 

    return BuildSigner.unknown; 
} 

對於任何涉及的證書,您只需找到一次散列並將其添加到列表中。

「查找散列一次」的最簡單方法可能是在顯示modulusHash的switch語句之前添加彈出式烤麪包,編譯您的應用,運行它,記下散列,刪除烘烤代碼並添加散列到名單。

或者,當我實現這一點,我創建具有單個活性和單TextView與主佈局ID tv一點樣板的應用程序,把這種成活動:

@Override 
public void onCreate(Bundle savedInstanceState) { 
    super.onCreate(savedInstanceState); 
    setContentView(R.layout.main); 
    int hash = 0; 
    try{ 
     PackageManager packageManager = getPackageManager(); 
     PackageInfo info = packageManager.getPackageInfo(
       "com.stackexchange.marvin", PackageManager.GET_SIGNATURES); 
     Signature[] signs = info.signatures; 
     CertificateFactory cf = CertificateFactory.getInstance("X.509"); 
     X509Certificate cert = (X509Certificate) cf.generateCertificate(
       new ByteArrayInputStream(signs[0].toByteArray())); 
     PublicKey key = cert.getPublicKey(); 
     hash = ((RSAPublicKey) key).getModulus().hashCode(); 
    }catch(Exception e){} 

    TextView tv = ((TextView)findViewById(R.id.tv)); 
    tv.setText("The Stack Exchange app's signature hash is " + hash + "."); 
    tv.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 24); 
} 

(改變com.stackexchange.marvin到你的應用程序的名稱),編譯這個迷你應用程序,並將APK發送給所有相關的開發人員,要求他們在他們的開發設備上運行它,並讓我知道顯示的散列。

+0

感謝您的信息...但是如何找到證書的哈希值?它是證書中'key alias'字符串的哈希值嗎? – 2014-09-09 06:48:59

+0

@VijayC我已經擴展了我的答案,請參閱更新的版本。 – balpha 2014-09-09 07:02:30

相關問題