增量更新工具类【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. [指南] 15分钟学会MySQL(Linux版)

    原文链接:http://www.mysqlpub.com/thread-348-1-1.html 原创出处:MySQLpub.com  , 作者:kider  ,转载请注明作者和出处,并不能用于商业用 ...

  2. 20155205 信息安全技术第二次实验 Windows口令破解

    20155205 信息安全技术第二次实验 Windows口令破解 实验原理 一.口令破解方法 口令破解主要有两种方法:字典破解和暴力破解. 字典破解是指通过破解者对管理员的了解,猜测其可能使用某些信息 ...

  3. session(会话)研究(一)基础

    一.Session对象的生成 session对象生成的过程,可以通过一个直观图进行观察. 也就是说,客户第一次请求访问时,Cookie中是没有SessionID的.在第一次访问之后,由服务器生成一个S ...

  4. 树形控件(CTreeCtrl和CTreeView)

    如何插入数据项目? 如何添加鼠标右击事件? 插入数据项 通过InsertItem()方法,有四种重载样式: HTREEITEM InsertItem(LPTVINSERTSTRUCT lpInsert ...

  5. C++函数的传值调用&指针调用&引用调用

    目录 传值调用 指针调用 引用调用 传值调用 该方法把参数的实际值复制给函数的形式参数.在这种情况下,修改函数内的形式参数对实际参数没有影响. #include<iostream> usi ...

  6. Eclipse添加servlet-api.jar库的引用

    右键Application-->Properties-->Java Build Path-->Libraries-->Add External JARs-->servle ...

  7. 配置SecureCRT密钥连接Linux

    SSH公钥加密的方式使得对方即使截取了帐号密码,在没有公钥私钥的情况下,依然无法远程ssh登录系统,这样就大大加强了远程登录的安全性. 1.        编辑配置文件 /etc/ssh/sshd_c ...

  8. noip第6课作业

    1.    数据统计 [问题描述] 输入N个整数,求出它们的最小值.最大值和平均值(保留3位小数).输入保证这些数都是不超过1000的整数.(1<=N<=1000) [样例输入] 8 2 ...

  9. JAVA作业之两数的加减乘除

    1.设计思路 把输入的字符转化为计算的数字问题,再以对话框的形式输入输出加减乘除的结果问题. 2.程序流程图 3.源代码 4.实验结果

  10. include require include_once require_once

    include 使用方法: include "test.php"; 一般是放在流程控制的处理部分中使用,将文件内容引入.PHP程序在遇到include语句时,才将它读进来,这种方式 ...