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

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

public Signature getPackageSignature(Context context, String packageName){
                PackageManager pm = context.getPackageManager();
                List apps = pm.getInstalledPackages(PackageManager.GET_SIGNATURES);
                Iterator it = apps.iterator();
                while(it.hasNext()){
                        PackageInfo info = it.next();
                        if(info.packageName.equals(packageName)){
                                return info.signatures[0];
                        }
                }
                return null;
        }

2.根据文件路径获取未安装的apk的签名信息
由于android平台本身的一个小bug,使用PackageManager方式获取未安装的apk文件的签名会稍微费事一点。
(android平台的这个小bug有些狗血,是因为PackageManager的的getPackageArchiveInfo中少了如下代码的原因导致)
缺少的代码:

if ((flags & GET_SIGNATURES) != 0)
            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函数,如下:
@SuppressWarnings("unchecked")
        public PackageInfo getPackageArchiveInfo(String archiveFilePath, int flags){
        // Workaround for https://code.google.com/p/android/issues/detail?id=9151#c8
        try{
            Class packageParserClass = Class.forName(
                    "android.content.pm.PackageParser");
            Class[] innerClasses = packageParserClass.getDeclaredClasses();
            Class packageParserPackageClass = null;
            for (Class innerClass : innerClasses){
                if (0 == innerClass.getName().compareTo("android.content.pm.PackageParser$Package")){
                    packageParserPackageClass = innerClass;
                    break;
                }
            }
            Constructor packageParserConstructor = packageParserClass.getConstructor(
                    String.class);
            Method parsePackageMethod = packageParserClass.getDeclaredMethod(
                    "parsePackage", File.class, String.class, DisplayMetrics.class, int.class);
            Method collectCertificatesMethod = packageParserClass.getDeclaredMethod(
                    "collectCertificates", packageParserPackageClass, int.class);
            Method generatePackageInfoMethod = packageParserClass.getDeclaredMethod(
                    "generatePackageInfo", packageParserPackageClass, int[].class, int.class, long.class, long.class);
            packageParserConstructor.setAccessible(true);
            parsePackageMethod.setAccessible(true);
            collectCertificatesMethod.setAccessible(true);
            generatePackageInfoMethod.setAccessible(true);

            Object packageParser = packageParserConstructor.newInstance(archiveFilePath);

            DisplayMetrics metrics = new DisplayMetrics();
            metrics.setToDefaults();

            final File sourceFile = new File(archiveFilePath);

            Object pkg = parsePackageMethod.invoke(
                    packageParser,
                    sourceFile,
                    archiveFilePath,
                    metrics,
                    0);
            if (pkg == null){
                return null;
            }

            if ((flags & android.content.pm.PackageManager.GET_SIGNATURES) != 0){
                collectCertificatesMethod.invoke(packageParser, pkg, 0);
            }

            return (PackageInfo)generatePackageInfoMethod.invoke(null, pkg, null, flags, 0, 0);
        }
        catch (Exception e)
        {
            Log.e("Signature Monitor",
                "android.content.pm.PackageParser reflection failed: " + e.toString());
        }

        return null;
    }
(2)使用自定义的getPackageArchiveInfo函数获取PackageInfo,从而获取签名信息,如下:
/**
         * 
         * @param context
         * @param apkFile 文件的全路径信息(包括apk文件的名称),如果是无效的apk文件,返回值为null
         * @return
         */
        public Signature getApkSignatureByFilePath(Context context, String apkFile){
                PackageInfo newInfo = getPackageArchiveInfo(apkFile, PackageManager.GET_ACTIVITIES | PackageManager.GET_SIGNATURES);
                if(newInfo != null){
                        if(newInfo.signatures != null && newInfo.signatures.length >0){
                                return newInfo.signatures[0];
                        }
                }
                return null;
        }

你可能感兴趣的:(Android)