Android 开发工具类 35_PatchUtils

增量更新工具类【https://github.com/cundong/SmartAppUpdates】

  1 import java.io.File;
  2 
  3 import android.app.Activity;
  4 import android.app.ProgressDialog;
  5 import android.content.Context;
  6 import android.content.Intent;
  7 import android.net.Uri;
  8 import android.os.AsyncTask;
  9 import android.os.Bundle;
 10 import android.text.TextUtils;
 11 import android.view.View;
 12 import android.view.View.OnClickListener;
 13 import android.widget.Button;
 14 import android.widget.TextView;
 15 import android.widget.Toast;
 16 
 17 import com.cundong.utils.PatchUtils;
 18 import com.example.test.util.ApkUtils;
 19 import com.example.test.util.SignUtils;
 20 import com.example.test2.R;
 21 
 22 /**
 23  * 类说明: ApkPatchLibrary 使用 Demo
 24  * 
 25  * @author  Cundong
 26  * @version 1.5
 27  */
 28 public class MainActivity extends Activity {
 29 
 30     // 合成成功
 31     private static final int WHAT_SUCCESS = 1;
 32 
 33     // 合成的APK签名和已安装的签名不一致
 34     private static final int WHAT_FAIL_SING = -1;
 35 
 36     // 合成失败
 37     private static final int WHAT_FAIL_ERROR = -2;
 38 
 39     // 获取源文件失败
 40     private static final int WHAT_FAIL_GET_SOURCE = -3;
 41 
 42     private Context mContext = null;
 43 
 44     private ProgressDialog mProgressDialog;
 45     private TextView mResultView;
 46     private Button mStartButton, mGithubButton;
 47 
 48     private long mBeginTime, mEndTime;
 49 
 50     @Override
 51     protected void onCreate(Bundle savedInstanceState) {
 52         super.onCreate(savedInstanceState);
 53         setContentView(R.layout.activity_main);
 54 
 55         mContext = getApplicationContext();
 56 
 57         mProgressDialog = new ProgressDialog(this);
 58         mProgressDialog.setProgressStyle(ProgressDialog.STYLE_SPINNER);
 59         mProgressDialog.setMessage("doing..");
 60         mProgressDialog.setCancelable(false);
 61 
 62         mResultView = (TextView) findViewById(R.id.textview4);
 63         mStartButton = (Button) findViewById(R.id.start_btn);
 64         mGithubButton = (Button) findViewById(R.id.github_btn);
 65 
 66         mStartButton.setOnClickListener(new OnClickListener() {
 67 
 68             @Override
 69             public void onClick(View arg0) {
 70 
 71                 File patchFile = new File(Constants.PATCH_PATH);
 72                 
 73                 if (!ApkUtils.isInstalled(mContext, Constants.TEST_PACKAGENAME)) {
 74                     Toast.makeText(mContext, getString(R.string.demo_info1),
 75                             Toast.LENGTH_LONG).show();
 76                 } else if (!patchFile.exists()) {
 77                     Toast.makeText(mContext, getString(R.string.demo_info2),
 78                             Toast.LENGTH_LONG).show();
 79                 } else {
 80                     new PatchApkTask().execute();
 81                 }
 82             }
 83         });
 84 
 85         mGithubButton.setOnClickListener(new OnClickListener() {
 86 
 87             @Override
 88             public void onClick(View v) {
 89                 Intent intent = new Intent("android.intent.action.VIEW", Uri.parse("https://github.com/cundong/SmartAppUpdates"));
 90                 startActivity(intent);
 91             }
 92         });
 93     }
 94     
 95     private class PatchApkTask extends AsyncTask<String, Void, Integer> {
 96 
 97         @Override
 98         protected void onPreExecute() {
 99             super.onPreExecute();
100             
101             mProgressDialog.show();
102             
103             mResultView.setText("");
104             mBeginTime = System.currentTimeMillis();
105         }
106 
107         @Override
108         protected Integer doInBackground(String... params) {
109 
110             String oldApkSource = ApkUtils.getSourceApkPath(mContext,
111                     Constants.TEST_PACKAGENAME);
112 
113             if (!TextUtils.isEmpty(oldApkSource)) {
114 
115                 int patchResult = PatchUtils.patch(oldApkSource,
116                         Constants.NEW_APK_PATH, Constants.PATCH_PATH);
117 
118                 if (patchResult == 0) {
119 
120                     String signatureNew = SignUtils
121                             .getUnInstalledApkSignature(Constants.NEW_APK_PATH);
122 
123                     String signatureSource = SignUtils
124                             .getInstalledApkSignature(mContext,
125                                     Constants.TEST_PACKAGENAME);
126                     
127                     if (!TextUtils.isEmpty(signatureNew)
128                             && !TextUtils.isEmpty(signatureSource)
129                             && signatureNew.equals(signatureSource)) {
130                         return WHAT_SUCCESS;
131                     } else {
132                         return WHAT_FAIL_SING;
133                     }
134                 } else {
135                     return WHAT_FAIL_ERROR;
136                 }
137             } else {
138                 return WHAT_FAIL_GET_SOURCE;
139             }
140         }
141         
142         @Override
143         protected void onPostExecute(Integer result) {
144             super.onPostExecute(result);
145             
146             if (mProgressDialog.isShowing()) {
147                 mProgressDialog.dismiss();
148             }
149             
150             mEndTime = System.currentTimeMillis();
151             mResultView.setText("耗时: " + (mEndTime - mBeginTime) + "ms");
152             
153             switch (result) {
154                 case WHAT_SUCCESS: {
155                     
156                     String text = "新apk已合成成功:" + Constants.NEW_APK_PATH;
157                     showShortToast(text);
158                     
159                     ApkUtils.installApk(MainActivity.this, Constants.NEW_APK_PATH);
160                     break;
161                 }
162                 case WHAT_FAIL_SING: {
163                     String text = "新apk已合成失败,签名不一致";
164                     showShortToast(text);
165                     break;
166                 }
167                 case WHAT_FAIL_ERROR: {
168                     String text = "新apk已合成失败";
169                     showShortToast(text);
170                     break;
171                 }
172                 case WHAT_FAIL_GET_SOURCE: {
173                     String text = "无法获取packageName为" + Constants.TEST_PACKAGENAME
174                             + "的源apk文件,只能整包更新了!";
175                     showShortToast(text);
176                     break;
177                 }
178             }
179         }
180     }
181     
182     private void showShortToast(final String text) {
183 
184         Toast.makeText(mContext, text, Toast.LENGTH_SHORT).show();
185     }
186     
187     static {
188         System.loadLibrary("ApkPatchLibrary");
189     }
190 }

APK 工具类

 1 import android.content.Context;
 2 import android.content.Intent;
 3 import android.content.pm.ApplicationInfo;
 4 import android.content.pm.PackageManager;
 5 import android.content.pm.PackageManager.NameNotFoundException;
 6 import android.net.Uri;
 7 import android.text.TextUtils;
 8 
 9 /**
10  * 类说明:  Apk工具类
11  * 
12  * @author     Cundong
13  * @date     2013-9-6
14  * @version 1.0
15  */
16 public class ApkUtils {
17 
18     public static boolean isInstalled(Context context, String packageName) {
19         PackageManager pm = context.getPackageManager();
20         boolean installed = false;
21         try {
22             pm.getPackageInfo(packageName, PackageManager.GET_ACTIVITIES);
23             installed = true;
24         } catch (Exception e) {
25             e.printStackTrace();
26         }
27 
28         return installed;
29     }
30 
31     /**
32      * 获取已安装Apk文件的源Apk文件
33      * 如:/data/app/com.sina.weibo-1.apk
34      * 
35      * @param context
36      * @param packageName
37      * @return
38      */
39     public static String getSourceApkPath(Context context, String packageName) {
40         if (TextUtils.isEmpty(packageName))
41             return null;
42 
43         try {
44             ApplicationInfo appInfo = context.getPackageManager()
45                     .getApplicationInfo(packageName, 0);
46             return appInfo.sourceDir;
47         } catch (NameNotFoundException e) {
48             e.printStackTrace();
49         }
50 
51         return null;
52     }
53 
54     /**
55      * 安装Apk
56      * 
57      * @param context
58      * @param apkPath
59      */
60     public static void installApk(Context context, String apkPath) {
61 
62         Intent intent = new Intent(Intent.ACTION_VIEW);
63         intent.setDataAndType(Uri.parse("file://" + apkPath),
64                 "application/vnd.android.package-archive");
65 
66         context.startActivity(intent);
67     }
68 }

apk 签名信息获取工具类

  1 import java.io.File;
  2 import java.lang.reflect.Constructor;
  3 import java.lang.reflect.Field;
  4 import java.lang.reflect.Method;
  5 import java.util.Iterator;
  6 import java.util.List;
  7 
  8 import android.content.Context;
  9 import android.content.pm.PackageInfo;
 10 import android.content.pm.PackageManager;
 11 import android.content.pm.Signature;
 12 import android.util.DisplayMetrics;
 13 
 14 /**
 15  * 类说明:  apk 签名信息获取工具类
 16  * 
 17  * @author     Cundong
 18  * @date     2013-9-6
 19  * @version 1.0
 20  */
 21 public class SignUtils {
 22 
 23     /**
 24      * 获取未安装Apk的签名
 25      * 
 26      * @param apkPath
 27      * @return
 28      */
 29     public static String getUnInstalledApkSignature(String apkPath) {
 30         String PATH_PackageParser = "android.content.pm.PackageParser";
 31 
 32         try {
 33             Class<?> pkgParserCls = Class.forName(PATH_PackageParser);
 34             Class<?>[] typeArgs = new Class[1];
 35             typeArgs[0] = String.class;
 36             Constructor<?> pkgParserCt = pkgParserCls.getConstructor(typeArgs);
 37             Object[] valueArgs = new Object[1];
 38             valueArgs[0] = apkPath;
 39             Object pkgParser = pkgParserCt.newInstance(valueArgs);
 40 
 41             DisplayMetrics metrics = new DisplayMetrics();
 42             metrics.setToDefaults();
 43 
 44             typeArgs = new Class[4];
 45             typeArgs[0] = File.class;
 46             typeArgs[1] = String.class;
 47             typeArgs[2] = DisplayMetrics.class;
 48             typeArgs[3] = Integer.TYPE;
 49 
 50             Method pkgParser_parsePackageMtd = pkgParserCls.getDeclaredMethod(
 51                     "parsePackage", typeArgs);
 52             valueArgs = new Object[4];
 53             valueArgs[0] = new File(apkPath);
 54             valueArgs[1] = apkPath;
 55             valueArgs[2] = metrics;
 56             valueArgs[3] = PackageManager.GET_SIGNATURES;
 57             Object pkgParserPkg = pkgParser_parsePackageMtd.invoke(pkgParser,
 58                     valueArgs);
 59 
 60             typeArgs = new Class[2];
 61             typeArgs[0] = pkgParserPkg.getClass();
 62             typeArgs[1] = Integer.TYPE;
 63 
 64             Method pkgParser_collectCertificatesMtd = pkgParserCls
 65                     .getDeclaredMethod("collectCertificates", typeArgs);
 66             valueArgs = new Object[2];
 67             valueArgs[0] = pkgParserPkg;
 68             valueArgs[1] = PackageManager.GET_SIGNATURES;
 69             pkgParser_collectCertificatesMtd.invoke(pkgParser, valueArgs);
 70 
 71             Field packageInfoFld = pkgParserPkg.getClass().getDeclaredField(
 72                     "mSignatures");
 73             Signature[] info = (Signature[]) packageInfoFld.get(pkgParserPkg);
 74             return info[0].toCharsString();
 75         } catch (Exception e) {
 76             e.printStackTrace();
 77         }
 78 
 79         return null;
 80     }
 81 
 82     /**
 83      * 获取已安装apk签名
 84      * 
 85      * @param context
 86      * @param packageName
 87      * @return
 88      */
 89     public static String getInstalledApkSignature(Context context,
 90             String packageName) {
 91         PackageManager pm = context.getPackageManager();
 92         List<PackageInfo> apps = pm
 93                 .getInstalledPackages(PackageManager.GET_SIGNATURES);
 94 
 95         Iterator<PackageInfo> iter = apps.iterator();
 96         while (iter.hasNext()) {
 97             PackageInfo packageinfo = iter.next();
 98             String thisName = packageinfo.packageName;
 99             if (thisName.equals(packageName)) {
100                 return packageinfo.signatures[0].toCharsString();
101             }
102         }
103 
104         return null;
105     }
106 }
原文地址:https://www.cnblogs.com/renzimu/p/4720597.html