获取已安装或未安装的apk签名

本文提供了一段Java代码,用于从已安装的应用程序中获取其签名信息,以及如何在未安装的情况下获取未安装apk文件的签名。通过自定义函数解决Android平台的小bug,实现获取未安装apk文件的签名。

出处: http://lynen.iteye.com/blog/1700126

某些时候需要获取已安装的apk或者是未安装的apk的签名信息,以下代码片段将会很有用。

1.通过app的packageName获取已安装的apk的签名信息

 

Java代码   收藏代码
  1. public Signature getPackageSignature(Context context, String packageName){  
  2.         PackageManager pm = context.getPackageManager();  
  3.         List<PackageInfo> apps = pm.getInstalledPackages(PackageManager.GET_SIGNATURES);  
  4.         Iterator<PackageInfo> it = apps.iterator();  
  5.         while(it.hasNext()){  
  6.             PackageInfo info = it.next();  
  7.             if(info.packageName.equals(packageName)){  
  8.                 return info.signatures[0];  
  9.             }  
  10.         }  
  11.         return null;  
  12.     }  

 

2.根据文件路径获取未安装的apk的签名信息

由于android平台本身的一个小bug,使用PackageManager方式获取未安装的apk文件的签名会稍微费事一点。

(android平台的这个小bug有些狗血,是因为PackageManager的的getPackageArchiveInfo中少了如下代码的原因导致)

缺少的代码:

 

Java代码   收藏代码
  1. if ((flags & GET_SIGNATURES) != 0)  
  2.             packageParser.collectCertificates(pkg, 0);  

问题的详细信息可以查看以下链接:

https://code.google.com/p/android/issues/detail?id=9151#c8

https://android-review.googlesource.com/#/c/18769/1/core/java/android/content/pm/PackageManager.java

 

这样一来,获取apk文件的签名方式将会变得稍微啰嗦一点

(1)首先自定义一个getPackageArchiveInfo函数,如下:

Java代码   收藏代码
  1. @SuppressWarnings("unchecked")  
  2.     public PackageInfo getPackageArchiveInfo(String archiveFilePath, int flags){  
  3.         // Workaround for https://code.google.com/p/android/issues/detail?id=9151#c8  
  4.         try{  
  5.             Class packageParserClass = Class.forName(  
  6.                     "android.content.pm.PackageParser");  
  7.             Class[] innerClasses = packageParserClass.getDeclaredClasses();  
  8.             Class packageParserPackageClass = null;  
  9.             for (Class innerClass : innerClasses){  
  10.                 if (0 == innerClass.getName().compareTo("android.content.pm.PackageParser$Package")){  
  11.                     packageParserPackageClass = innerClass;  
  12.                     break;  
  13.                 }  
  14.             }  
  15.             Constructor packageParserConstructor = packageParserClass.getConstructor(  
  16.                     String.class);  
  17.             Method parsePackageMethod = packageParserClass.getDeclaredMethod(  
  18.                     "parsePackage", File.class, String.class, DisplayMetrics.classint.class);  
  19.             Method collectCertificatesMethod = packageParserClass.getDeclaredMethod(  
  20.                     "collectCertificates", packageParserPackageClass, int.class);  
  21.             Method generatePackageInfoMethod = packageParserClass.getDeclaredMethod(  
  22.                     "generatePackageInfo", packageParserPackageClass, int[].classint.classlong.classlong.class);  
  23.             packageParserConstructor.setAccessible(true);  
  24.             parsePackageMethod.setAccessible(true);  
  25.             collectCertificatesMethod.setAccessible(true);  
  26.             generatePackageInfoMethod.setAccessible(true);  
  27.               
  28.             Object packageParser = packageParserConstructor.newInstance(archiveFilePath);  
  29.       
  30.             DisplayMetrics metrics = new DisplayMetrics();  
  31.             metrics.setToDefaults();  
  32.               
  33.             final File sourceFile = new File(archiveFilePath);  
  34.   
  35.             Object pkg = parsePackageMethod.invoke(  
  36.                     packageParser,  
  37.                     sourceFile,  
  38.                     archiveFilePath,  
  39.                     metrics,  
  40.                     0);  
  41.             if (pkg == null){  
  42.                 return null;  
  43.             }  
  44.       
  45.             if ((flags & android.content.pm.PackageManager.GET_SIGNATURES) != 0){  
  46.                 collectCertificatesMethod.invoke(packageParser, pkg, 0);  
  47.             }  
  48.       
  49.             return (PackageInfo)generatePackageInfoMethod.invoke(null, pkg, null, flags, 00);  
  50.         }  
  51.         catch (Exception e)  
  52.         {  
  53.             Log.e("Signature Monitor",  
  54.                 "android.content.pm.PackageParser reflection failed: " + e.toString());  
  55.         }  
  56.   
  57.         return null;  
  58.     }  

 (2)使用自定义的getPackageArchiveInfo函数获取PackageInfo,从而获取签名信息,如下:

Java代码   收藏代码
  1. /** 
  2.      *  
  3.      * @param context 
  4.      * @param apkFile 文件的全路径信息(包括apk文件的名称),如果是无效的apk文件,返回值为null 
  5.      * @return 
  6.      */  
  7.     public Signature getApkSignatureByFilePath(Context context, String apkFile){  
  8.         PackageInfo newInfo = getPackageArchiveInfo(apkFile, PackageManager.GET_ACTIVITIES | PackageManager.GET_SIGNATURES);  
  9.         if(newInfo != null){  
  10.             if(newInfo.signatures != null && newInfo.signatures.length >0){  
  11.                 return newInfo.signatures[0];  
  12.             }  
  13.         }  
  14.         return null;  
  15.     }  
在 Android 设统中,安装签名APK 文件通常面临系统限制,因为 Android 系统强制要求所有应用必须经过数字签名才能安装[^1]。然而,在特定条件下,可以通过以下方式尝试安装签名APK 文件。 ### 通过调试桥(ADB)安装签名 APK 使用 Android Debug Bridge(ADB)工具可以在某些设备上安装签名APK 文件。首先需要在设备上启用开发者选项并打开 USB 调试模式。然后,通过 USB 将设备连接到计算机,并使用以下命令尝试安装: ```bash adb install app-unsigned.apk ``` 此方法在部分设备和系统版本中可能失败,特别是在 Android 7.0(Nougat)及以上版本中,系统对签名的验证更为严格[^2]。 ### 在模拟器上安装签名 APK Android 模拟器通常允许安装签名APK 文件。这是因为模拟器默认使用 `debug.keystore` 生成签名,而签名APK 可能会被接受安装,具体取决于模拟器配置和构建方式。在 Eclipse Android Studio 中开发时,选择“导出签名的应用程序包”即可直接部署到模拟器上进行测试[^1]。 ### 修改系统签名并重新打包 对于具有系统权限的设备(如定制 ROM root 设备),可以使用 `signapk.jar` 工具对签名APK 进行重新签名,使其具备系统签名权限。例如,使用如下命令对 APK 进行签名: ```bash java -jar signapk.jar platform.x509.pem platform.pk8 app-debug.apk app-debug-signed.apk ``` 此方法需要获取系统签名密钥(如 `platform.x509.pem` 和 `platform.pk8`),通常适用于系统级开发设备定制场景[^3]。 ### 使用第三方工具 ROM 某些第三方工具自定义 ROM(如 LineageOS)可能允许绕过签名验证机制,从而安装签名APK 文件。这些方法通常涉及修改系统行为禁用签名检查功能,但存在安全风险,不建议在生产环境中使用。 ### 注意事项 尽管上述方法可以实现签名 APK安装,但签名的应用缺乏身份认证和完整性保护,存在被篡改的风险。此外,Google Play 等官方应用商店不接受签名的应用,因此此类安装方式仅适用于测试特定开发需求。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值