package com.hotpatch;
import android.content.Context;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.Signature;
import android.os.Build;
import android.text.TextUtils;
import android.util.DisplayMetrics;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.math.BigInteger;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Iterator;
import java.util.List;
public class Utils {
/**
* Get the Signature of apk file which is not installed.
*
* @param apkPath
* @return
*/
public static String getApkSignature(String apkPath) {
String PATH_PackageParser = "android.content.pm.PackageParser";
try {
Class<?> pkgParserCls = Class.forName(PATH_PackageParser);
Class<?>[] typeArgs = new Class[1];
typeArgs[0] = String.class;
Object[] valueArgs = new Object[1];
valueArgs[0] = apkPath;
Object pkgParser;
if (Build.VERSION.SDK_INT > 19) {
pkgParser = pkgParserCls.newInstance();
} else {
Constructor constructor = pkgParserCls.getConstructor(typeArgs);
pkgParser = constructor.newInstance(valueArgs);
}
DisplayMetrics metrics = new DisplayMetrics();
metrics.setToDefaults();
Object pkgParserPkg = null;
if (Build.VERSION.SDK_INT > 19) {
typeArgs = new Class[2];
typeArgs[0] = File.class;
typeArgs[1] = int.class;
Method pkgParser_parsePackageMtd = pkgParserCls.getDeclaredMethod(
"parsePackage", typeArgs);
pkgParser_parsePackageMtd.setAccessible(true);
valueArgs = new Object[2];
valueArgs[0] = new File(apkPath);
valueArgs[1] = PackageManager.GET_SIGNATURES;
pkgParserPkg = pkgParser_parsePackageMtd.invoke(pkgParser,
valueArgs);
} else {
typeArgs = new Class[4];
typeArgs[0] = File.class;
typeArgs[1] = String.class;
typeArgs[2] = DisplayMetrics.class;
typeArgs[3] = int.class;
Method pkgParser_parsePackageMtd = pkgParserCls.getDeclaredMethod(
"parsePackage", typeArgs);
pkgParser_parsePackageMtd.setAccessible(true);
valueArgs = new Object[4];
valueArgs[0] = new File(apkPath);
valueArgs[1] = apkPath;
valueArgs[2] = metrics;
valueArgs[3] = PackageManager.GET_SIGNATURES;
pkgParserPkg = pkgParser_parsePackageMtd.invoke(pkgParser,
valueArgs);
}
typeArgs = new Class[2];
typeArgs[0] = pkgParserPkg.getClass();
typeArgs[1] = int.class;
Method pkgParser_collectCertificatesMtd = pkgParserCls.getDeclaredMethod("collectCertificates", typeArgs);
valueArgs = new Object[2];
valueArgs[0] = pkgParserPkg;
valueArgs[1] = PackageManager.GET_SIGNATURES;
pkgParser_collectCertificatesMtd.invoke(pkgParser, valueArgs);
Field packageInfoFld = pkgParserPkg.getClass().getDeclaredField(
"mSignatures");
Signature[] info = (Signature[]) packageInfoFld.get(pkgParserPkg);
return info[0].toCharsString();
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
/**
* Get the Signature of the apk file which package name is @param packageName
*
* @param context
* @param packageName
* @return packageSignatrue
*/
public static String getInstallPackageSignature(Context context,
String packageName) {
PackageManager pm = context.getPackageManager();
List<PackageInfo> apps = pm
.getInstalledPackages(PackageManager.GET_SIGNATURES);
Iterator<PackageInfo> iter = apps.iterator();
while (iter.hasNext()) {
PackageInfo packageinfo = iter.next();
String thisName = packageinfo.packageName;
if (thisName.equals(packageName)) {
return packageinfo.signatures[0].toCharsString();
}
}
return null;
}
public static String getMd5ByFile(File file) {
String value = null;
FileInputStream in=null;
try {
in = new FileInputStream(file);
MappedByteBuffer byteBuffer = in.getChannel().map(FileChannel.MapMode.READ_ONLY, 0, file.length());
MessageDigest md5 = MessageDigest.getInstance("MD5");
md5.update(byteBuffer);
BigInteger bi = new BigInteger(1, md5.digest());
value = bi.toString(16);
} catch (Exception e) {
e.printStackTrace();
} finally {
if (null != in) {
try {
in.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return value;
}
public static String md5(String string) {
byte[] hash;
try {
hash = MessageDigest.getInstance("MD5").digest(string.getBytes("UTF-8"));
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException("Huh, MD5 should be supported?", e);
} catch (UnsupportedEncodingException e) {
throw new RuntimeException("Huh, UTF-8 should be supported?", e);
}
StringBuilder hex = new StringBuilder(hash.length * 2);
for (byte b : hash) {
if ((b & 0xFF) < 0x10) hex.append("0");
hex.append(Integer.toHexString(b & 0xFF));
}
return hex.toString();
}
public static String getCacheApkFilePath(Context ctx,String fileUrl){
return ctx.getExternalCacheDir()+"/"+md5(fileUrl)+".apk";
}
/**
*
* Compare the patch apk to the apk which package name is ctx.getPackageName()
* @param ctx
* @param apkFile the patch apk
* @return the result of compare
* **/
public static boolean isSignEqual(Context ctx,String apkFile){
String packageSign=getInstallPackageSignature(ctx,ctx.getPackageName());
String apkFileSign=getApkSignature(apkFile);
return TextUtils.equals(packageSign,apkFileSign);
}
public static String getVersionName(Context context) {
try {
PackageManager packageManager = context.getPackageManager();
PackageInfo packInfo = packageManager.getPackageInfo(context.getPackageName(), 0);
String version =String.valueOf(packInfo.versionName);
return version;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
}