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

 import java.io.File;

 import android.app.Activity;
import android.app.ProgressDialog;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Bundle;
import android.text.TextUtils;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast; import com.cundong.utils.PatchUtils;
import com.example.test.util.ApkUtils;
import com.example.test.util.SignUtils;
import com.example.test2.R; /**
* 类说明: ApkPatchLibrary 使用 Demo
*
* @author Cundong
* @version 1.5
*/
public class MainActivity extends Activity { // 合成成功
private static final int WHAT_SUCCESS = 1; // 合成的APK签名和已安装的签名不一致
private static final int WHAT_FAIL_SING = -1; // 合成失败
private static final int WHAT_FAIL_ERROR = -2; // 获取源文件失败
private static final int WHAT_FAIL_GET_SOURCE = -3; private Context mContext = null; private ProgressDialog mProgressDialog;
private TextView mResultView;
private Button mStartButton, mGithubButton; private long mBeginTime, mEndTime; @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main); mContext = getApplicationContext(); mProgressDialog = new ProgressDialog(this);
mProgressDialog.setProgressStyle(ProgressDialog.STYLE_SPINNER);
mProgressDialog.setMessage("doing..");
mProgressDialog.setCancelable(false); mResultView = (TextView) findViewById(R.id.textview4);
mStartButton = (Button) findViewById(R.id.start_btn);
mGithubButton = (Button) findViewById(R.id.github_btn); mStartButton.setOnClickListener(new OnClickListener() { @Override
public void onClick(View arg0) { File patchFile = new File(Constants.PATCH_PATH); if (!ApkUtils.isInstalled(mContext, Constants.TEST_PACKAGENAME)) {
Toast.makeText(mContext, getString(R.string.demo_info1),
Toast.LENGTH_LONG).show();
} else if (!patchFile.exists()) {
Toast.makeText(mContext, getString(R.string.demo_info2),
Toast.LENGTH_LONG).show();
} else {
new PatchApkTask().execute();
}
}
}); mGithubButton.setOnClickListener(new OnClickListener() { @Override
public void onClick(View v) {
Intent intent = new Intent("android.intent.action.VIEW", Uri.parse("https://github.com/cundong/SmartAppUpdates"));
startActivity(intent);
}
});
} private class PatchApkTask extends AsyncTask<String, Void, Integer> { @Override
protected void onPreExecute() {
super.onPreExecute(); mProgressDialog.show(); mResultView.setText("");
mBeginTime = System.currentTimeMillis();
} @Override
protected Integer doInBackground(String... params) { String oldApkSource = ApkUtils.getSourceApkPath(mContext,
Constants.TEST_PACKAGENAME); if (!TextUtils.isEmpty(oldApkSource)) { int patchResult = PatchUtils.patch(oldApkSource,
Constants.NEW_APK_PATH, Constants.PATCH_PATH); if (patchResult == 0) { String signatureNew = SignUtils
.getUnInstalledApkSignature(Constants.NEW_APK_PATH); String signatureSource = SignUtils
.getInstalledApkSignature(mContext,
Constants.TEST_PACKAGENAME); if (!TextUtils.isEmpty(signatureNew)
&& !TextUtils.isEmpty(signatureSource)
&& signatureNew.equals(signatureSource)) {
return WHAT_SUCCESS;
} else {
return WHAT_FAIL_SING;
}
} else {
return WHAT_FAIL_ERROR;
}
} else {
return WHAT_FAIL_GET_SOURCE;
}
} @Override
protected void onPostExecute(Integer result) {
super.onPostExecute(result); if (mProgressDialog.isShowing()) {
mProgressDialog.dismiss();
} mEndTime = System.currentTimeMillis();
mResultView.setText("耗时: " + (mEndTime - mBeginTime) + "ms"); switch (result) {
case WHAT_SUCCESS: { String text = "新apk已合成成功:" + Constants.NEW_APK_PATH;
showShortToast(text); ApkUtils.installApk(MainActivity.this, Constants.NEW_APK_PATH);
break;
}
case WHAT_FAIL_SING: {
String text = "新apk已合成失败,签名不一致";
showShortToast(text);
break;
}
case WHAT_FAIL_ERROR: {
String text = "新apk已合成失败";
showShortToast(text);
break;
}
case WHAT_FAIL_GET_SOURCE: {
String text = "无法获取packageName为" + Constants.TEST_PACKAGENAME
+ "的源apk文件,只能整包更新了!";
showShortToast(text);
break;
}
}
}
} private void showShortToast(final String text) { Toast.makeText(mContext, text, Toast.LENGTH_SHORT).show();
} static {
System.loadLibrary("ApkPatchLibrary");
}
}

APK 工具类

 import android.content.Context;
import android.content.Intent;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.net.Uri;
import android.text.TextUtils; /**
* 类说明: Apk工具类
*
* @author Cundong
* @date 2013-9-6
* @version 1.0
*/
public class ApkUtils { public static boolean isInstalled(Context context, String packageName) {
PackageManager pm = context.getPackageManager();
boolean installed = false;
try {
pm.getPackageInfo(packageName, PackageManager.GET_ACTIVITIES);
installed = true;
} catch (Exception e) {
e.printStackTrace();
} return installed;
} /**
* 获取已安装Apk文件的源Apk文件
* 如:/data/app/com.sina.weibo-1.apk
*
* @param context
* @param packageName
* @return
*/
public static String getSourceApkPath(Context context, String packageName) {
if (TextUtils.isEmpty(packageName))
return null; try {
ApplicationInfo appInfo = context.getPackageManager()
.getApplicationInfo(packageName, 0);
return appInfo.sourceDir;
} catch (NameNotFoundException e) {
e.printStackTrace();
} return null;
} /**
* 安装Apk
*
* @param context
* @param apkPath
*/
public static void installApk(Context context, String apkPath) { Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setDataAndType(Uri.parse("file://" + apkPath),
"application/vnd.android.package-archive"); context.startActivity(intent);
}
}

apk 签名信息获取工具类

 import java.io.File;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Iterator;
import java.util.List; import android.content.Context;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.Signature;
import android.util.DisplayMetrics; /**
* 类说明: apk 签名信息获取工具类
*
* @author Cundong
* @date 2013-9-6
* @version 1.0
*/
public class SignUtils { /**
* 获取未安装Apk的签名
*
* @param apkPath
* @return
*/
public static String getUnInstalledApkSignature(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;
Constructor<?> pkgParserCt = pkgParserCls.getConstructor(typeArgs);
Object[] valueArgs = new Object[1];
valueArgs[0] = apkPath;
Object pkgParser = pkgParserCt.newInstance(valueArgs); DisplayMetrics metrics = new DisplayMetrics();
metrics.setToDefaults(); typeArgs = new Class[4];
typeArgs[0] = File.class;
typeArgs[1] = String.class;
typeArgs[2] = DisplayMetrics.class;
typeArgs[3] = Integer.TYPE; Method pkgParser_parsePackageMtd = pkgParserCls.getDeclaredMethod(
"parsePackage", typeArgs);
valueArgs = new Object[4];
valueArgs[0] = new File(apkPath);
valueArgs[1] = apkPath;
valueArgs[2] = metrics;
valueArgs[3] = PackageManager.GET_SIGNATURES;
Object pkgParserPkg = pkgParser_parsePackageMtd.invoke(pkgParser,
valueArgs); typeArgs = new Class[2];
typeArgs[0] = pkgParserPkg.getClass();
typeArgs[1] = Integer.TYPE; 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;
} /**
* 获取已安装apk签名
*
* @param context
* @param packageName
* @return
*/
public static String getInstalledApkSignature(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;
}
}

Android 开发工具类 35_PatchUtils的更多相关文章

  1. Android开发工具类

    7种无须编程的DIY开发工具 你知道几个? 现如今,各种DIY开发工具不断的出现,使得企业和个人在短短几分钟内就能完成应用的创建和发布,大大节省了在时间和资金上的投入.此外,DIY工 具的出现,也帮助 ...

  2. android开发工具类之获得WIFI IP地址或者手机网络IP

    有的时候我们需要获得WIFI的IP地址获得手机网络的IP地址,这是一个工具类,专门解决这个问题,这里需要两个权限: <uses-permission android:name="and ...

  3. android开发工具类总结(一)

    一.日志工具类 Log.java public class L { private L() { /* 不可被实例化 */ throw new UnsupportedOperationException ...

  4. Android 开发工具类 13_ SaxService

    网络 xml 解析方式 package com.example.dashu_saxxml; import java.io.IOException; import java.io.InputStream ...

  5. Android 开发工具类 06_NetUtils

    跟网络相关的工具类: 1.判断网络是否连接: 2.判断是否是 wifi 连接: 3.打开网络设置界面: import android.app.Activity; import android.cont ...

  6. Android 开发工具类 03_HttpUtils

    Http 请求的工具类: 1.异步的 Get 请求: 2.异步的 Post 请求: 3.Get 请求,获得返回数据: 4.向指定 URL 发送 POST方法的请求. import java.io.Bu ...

  7. Android 开发工具类 19_NetworkStateReceiver

    检测网络状态改变类: 1.注册网络状态广播: 2.检查网络状态: 3.注销网络状态广播: 4.获取当前网络状态,true为网络连接成功,否则网络连接失败: 5.注册网络连接观察者: 6.注销网络连接观 ...

  8. Android 开发工具类 27_多线程下载大文件

    多线程下载大文件时序图 FileDownloader.java package com.wangjialin.internet.service.downloader; import java.io.F ...

  9. Android 开发工具类 12_PullXmlTools

    xml 格式数据 <?xml version="1.0" encoding="UTF-8"?> <user-list> <user ...

随机推荐

  1. Vsftpd完全攻略(三)基于系统用户支持ftp上传 访问和vsftp安全设置

    原文链接:http://viong.blog.51cto.com/844766/261342 1.关闭匿名用户登录 ftp支持匿名登录是不安全,所以要禁止匿名ftp登录 在/etc/vsftpd/vs ...

  2. C#窗体操作的小技巧

    窗体在屏幕居中 ) - (), (Screen.GetBounds() - (), this.Width, this.Height, BoundsSpecified.Location);

  3. 1.8.1suspend与resume方法使用

    暂停线程意味着线程还能恢复运行 suspend()方法暂停线程.resume()恢复线程 测试如下 package com.cky.thread; /** * Created by edison on ...

  4. 1.2.1继承Thread类

    实现多线程的方法有2种:方法一是继承Thread,方法二是实现Runnerable接口 使用继承Thread类的方法创建多线程的时候,最大的局限性就是不支持多继承,因为java语言的特点就是单继承,因 ...

  5. Objective-C的泛型

    WWDC2015的明星是Swift.在Swift语言到2.0以后会被开源,这其中包括了protocol扩展和一个新的错误处理API. 苹果的小baby已经长成,并且意料之中的获得了开发者的关注.但是在 ...

  6. (单调队列) Bad Hair Day -- POJ -- 3250

    http://poj.org/problem?id=3250 Bad Hair Day Time Limit: 2000MS   Memory Limit: 65536K Total Submissi ...

  7. (动态规划)Worm -- hdu -- 2151

    http://acm.hdu.edu.cn/showproblem.php?pid=2151 Worm Time Limit: 1000/1000 MS (Java/Others)    Memory ...

  8. Linux常用备份恢复工具

    在 Linux 中可以通过各种各样的方法来执行备份.所涉及的技术从非常简单的脚本驱动的方法,到精心设计的商业化软件.备份可以保存到远程网络设备.磁带驱动器和其他可移动媒体上.备份可以是基于文件的或基于 ...

  9. Swagger UI教程 API 文档神器 搭配Node使用

    ASP.NET Web API 使用Swagger生成在线帮助测试文档 Swagger 生成 ASP.NET Web API 前言 swagger ui是一个API在线文档生成和测试的利器,目前发现最 ...

  10. 一.认识python.变量.数据类型.条件if

    01.万恶之源-python基础 ⼀.python介绍  python的创始⼈为吉多·范罗苏姆(Guido van Rossum).1989年的圣诞节期间,吉多·范罗苏姆为了在阿姆斯特丹打发时间,决⼼ ...