认真查看第八项
1、获取version code
/**
* 获取包版本号version code
* @param context context
* @return 正常来说大于零,如果小于0(也就是为-1)时,则意为着获取失败
*/
public static int getVersionCode(Context context){
int versionCode = -1;
PackageManager packageManager = context.getPackageManager() ;
if (packageManager != null) {
PackageInfo packageInfo = null ;
try{
packageInfo = packageManager.getPackageInfo(context.getPackageName(),0) ;
}catch (PackageManager.NameNotFoundException e){
e.printStackTrace();
}
if (packageInfo != null){
versionCode = packageInfo.versionCode;
}
}
return versionCode;
}
/**
* 获取包版本号packageName
* @param context context
* @return 程序的包名
*/
public static String getPackageName(Context context){
String packageName = null;
PackageManager packageManager = context.getPackageManager() ;
if (packageManager != null) {
PackageInfo packageInfo = null ;
try{
packageInfo = packageManager.getPackageInfo(context.getPackageName(),0) ;
}catch (PackageManager.NameNotFoundException e){
e.printStackTrace();
}
if (packageInfo != null){
packageName = packageInfo.packageName;
}
}
return packageName;
}
3、获取application中的指定meta-data
/**
* 获取application中指定的meta-data
* @return 如果没有获取成功(没有对应值或者异常),则返回值为空
*/
public static String getAppMetaData(Context ctx, String key) {
if (ctx == null || TextUtils.isEmpty(key)) {
return null;
}
String resultData = null;
try {
PackageManager packageManager = ctx.getPackageManager();
if (packageManager != null) {
ApplicationInfo applicationInfo = packageManager.getApplicationInfo(ctx.getPackageName(), PackageManager.GET_META_DATA);
if (applicationInfo != null) {
if (applicationInfo.metaData != null) {
resultData = applicationInfo.metaData.getString(key);
}
}
}
} catch (PackageManager.NameNotFoundException e) {
e.printStackTrace();
}
return resultData;
}
4、调用系统下载
/**
* 调用系统下载模块下载apk
* @param context 上下文
* @param apkUrl apk对应的
* @param folderName 下载文件将要保存的sd卡文件夹名称
*/
@TargetApi(Build.VERSION_CODES.HONEYCOMB)
public static void downloadApkViaSystemMethod(Context context, String apkUrl, String folderName) {
//以下情况不予处理
if (context == null || TextUtils.isEmpty(apkUrl)) {
return;
}
if (TextUtils.isEmpty(folderName)) {
folderName = "XXX" ;
}
GlobalContext.mFolderName = folderName;
GlobalContext.mUrlDownload = apkUrl;
GlobalContext.mSharedprename = folderName + "XXX";
DownloadManager downloadManager = (DownloadManager) context.getSystemService(Context.DOWNLOAD_SERVICE);
DownloadManager.Request request = new DownloadManager.Request(Uri.parse(apkUrl));
isFolderExist(folderName);
//表示设置下载地址为sd卡的<span style="font-family: Arial, Helvetica, sans-serif;">XXX</span><span style="font-family: Arial, Helvetica, sans-serif;">文件夹,文件名为</span><span style="font-family: Arial, Helvetica, sans-serif;">XXX</span><span style="font-family: Arial, Helvetica, sans-serif;">.apk</span>
request.setDestinationInExternalPublicDir(folderName, "XXX.apk");
//设置下载中通知栏提示的标题
request.setTitle("标题XXX");
//设置下载中通知栏提示的介绍
request.setDescription("下载更新");
//表示下载进行中和下载完成的通知栏是否显示。
// 默认只显示下载中通知。VISIBILITY_VISIBLE_NOTIFY_COMPLETED表示下载完成后显示通知栏提示。
// VISIBILITY_HIDDEN表示不显示任何通知栏提示,
// 这个需要在AndroidMainfest中添加权限android.permission.DOWNLOAD_WITHOUT_NOTIFICATION.
request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED);
//表示下载允许的网络类型,默认在任何网络下都允许下载。有NETWORK_MOBILE、NETWORK_WIFI、NETWORK_BLUETOOTH三种及其组合可供选择。
// 如果只允许wifi下载,而当前网络为3g,则下载会等待。
request.setAllowedNetworkTypes(DownloadManager.Request.NETWORK_WIFI | DownloadManager.Request.NETWORK_MOBILE);
//移动网络情况下是否允许漫游。
request.setAllowedOverRoaming(false);
//设置下载文件的mineType。因为下载管理Ui中点击某个已下载完成文件及下载完成点击通知栏提示都会根据mimeType去打开文件
request.setMimeType("application/vnd.android.package-archive");
//调用downloadManager的enqueue接口进行下载,返回唯一的downloadId
long downloadId = downloadManager.enqueue(request);
LogAbout.d(TAG, "将downloadid存起来id=" + downloadId + "mSharedprename:" + mSharedprename);
//将downloadId存起来,以备后用
//java.lang.IllegalArgumentException: File http://www.lvye.cn/app/lvyehuodong.apk.xml contains a path separator
GlobalContext.storageDownloadId(downloadId, GlobalContext.SHARED_PRE_KEY, GlobalContext.SHARED_PRE_NAME, context);
}
class CompleteReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
LogAbout.d(TAG, "接收到广播了");
String action = intent.getAction();
if (TextUtils.isEmpty(action)) {
AlertUtil.alert("action为空", context);
return;
}
assert action != null;
if (action.equals(DownloadManager.ACTION_DOWNLOAD_COMPLETE)) {
LogAbout.d(TAG, "接收到的广播为下载完成");
// get complete download id
long completeDownloadId = intent.getLongExtra(DownloadManager.EXTRA_DOWNLOAD_ID, -1);
// to do here
long downloadId = GlobalContext.getDownloadId(SHARED_PRE_KEY, SHARED_PRE_NAME, context);
LogAbout.d(TAG, "接收到的downloadid为" + completeDownloadId + "本地存储的id为" + downloadId);
if (completeDownloadId == downloadId) {
String fileName = Environment.getExternalStoragePublicDirectory(GlobalContext.mFolderName).getAbsolutePath() + File.separator + "lvyehds.apk";
LogAbout.d(TAG, "apk文件路径为" + fileName);
if (TextUtils.isEmpty(fileName)) {
return;
}
VersionCheckUtil.installAPK(fileName, context);
//执行安装操作之后,取消监听
unRegisterReceiver(context);
}
}
}
}
6、安装apk文件
/**
* 安装apk文件
*/
public static void installAPK(String apkPath, Context context) {
File apkfile = new File(apkPath);
if (!apkfile.exists()) {
return;
}
// 通过Intent安装APK文件
Intent intent = new Intent(Intent.ACTION_VIEW);
//记得一定要加上此句,否则会报 Caused by: android.util.AndroidRuntimeException: Calling startActivity() from outside of an Activity context requires the FLAG_ACTIVITY_NEW_TASK flag. Is this really what you want?
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
//"application/vnd.android.package-archive"
intent.setDataAndType(Uri.parse("file://" + apkfile.toString()), "application/vnd.android.package-archive");
context.startActivity(intent);
// 如果不加上这句的话在apk安装完成之后点击单开会崩溃
android.os.Process.killProcess(android.os.Process.myPid());
}
7、卸载apk
/**
* 卸载应用程序
*/
public static void uninstallAPK(Context context, String packageName) {
if (TextUtils.isEmpty(packageName) || context == null) {
return;
}
LogAbout.d(TAG, "packagename" + packageName);
Uri packageURI = Uri.parse("package:" + packageName);
Intent uninstallIntent = new Intent(Intent.ACTION_DELETE, packageURI);
//记得一定要加上此句,否则会报 Caused by: android.util.AndroidRuntimeException: Calling startActivity() from outside of an Activity context requires the FLAG_ACTIVITY_NEW_TASK flag. Is this really what you want?
uninstallIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(uninstallIntent);
}
8、很重要的一个,就是需要判断是否需要下载,因为有可能用户中止暂停了下载,或者网络不好等原因造成的下载中断
/**
* 判断是否需要调用系统下载
* @param id 调用downloadManager.enqueue(request)时返回的id,that means an ID for the download, unique across the system. This ID is used to make future calls related to this download
* @return true if need download,else return false
*/
private static boolean isNeedDownload(long id, DownloadManager downloadManager) {
if (downloadManager == null) {
return true;
}
boolean isNeedDownloadAgain = true;
DownloadManager.Query query = new DownloadManager.Query();
query.setFilterById(id);
Cursor cursor = downloadManager.query(query);
if (cursor != null && cursor.moveToFirst()) {
int columnStatus = cursor.getColumnIndex(DownloadManager.COLUMN_STATUS);
int status = cursor.getInt(columnStatus);
int columnReason = cursor.getColumnIndex(DownloadManager.COLUMN_REASON);
int reason = cursor.getInt(columnReason);
switch (status) {
case DownloadManager.STATUS_FAILED:
switch (reason) {
case DownloadManager.ERROR_CANNOT_RESUME:
//some possibly transient error occurred but we can't resume the download
isNeedDownloadAgain = true;
AlertUtil.alert("开始重新下载更新!", mContext);
break;
case DownloadManager.ERROR_DEVICE_NOT_FOUND:
//no external storage device was found. Typically, this is because the SD card is not mounted
isNeedDownloadAgain = false;
AlertUtil.alert("请检查存储设备是否连接!", mContext);
break;
case DownloadManager.ERROR_FILE_ALREADY_EXISTS:
//the requested destination file already exists (the download manager will not overwrite an existing file)
isNeedDownloadAgain = false;
AlertUtil.alert("文件已存在,请查看下载列表!", mContext);
break;
case DownloadManager.ERROR_FILE_ERROR:
//a storage issue arises which doesn't fit under any other error code
isNeedDownloadAgain = true;
break;
case DownloadManager.ERROR_HTTP_DATA_ERROR:
//an error receiving or processing data occurred at the HTTP level
isNeedDownloadAgain = true;
break;
case DownloadManager.ERROR_INSUFFICIENT_SPACE://sd卡满了
//here was insufficient storage space. Typically, this is because the SD card is full
isNeedDownloadAgain = true;
AlertUtil.alert("请检查存储设备是否还有剩余空间!", mContext);
break;
case DownloadManager.ERROR_TOO_MANY_REDIRECTS:
//there were too many redirects
isNeedDownloadAgain = false;
AlertUtil.alert("服务器错误,请到官网下载更新。", mContext);
break;
case DownloadManager.ERROR_UNHANDLED_HTTP_CODE:
//an HTTP code was received that download manager can't handle
isNeedDownloadAgain = false;
AlertUtil.alert("服务器错误,请到官网下载更新。", mContext);
break;
case DownloadManager.ERROR_UNKNOWN:
//he download has completed with an error that doesn't fit under any other error code
isNeedDownloadAgain = false;
AlertUtil.alert("未知错误,请到官网下载更新。", mContext);
break;
}
break;
case DownloadManager.STATUS_PAUSED:
switch (reason) {
case DownloadManager.PAUSED_QUEUED_FOR_WIFI:
//the download exceeds a size limit for downloads over the mobile network and the download manager is waiting for a Wi-Fi connection to proceed
isNeedDownloadAgain = false;
AlertUtil.alert("下载已暂停,请检查网络连接!", mContext);
break;
case DownloadManager.PAUSED_UNKNOWN:
//the download is paused for some other reason
isNeedDownloadAgain = false;
AlertUtil.alert("下载已暂停,请等待重试或以其他方式下载更新!", mContext);
break;
case DownloadManager.PAUSED_WAITING_FOR_NETWORK:
//the download is waiting for network connectivity to proceed
isNeedDownloadAgain = false;
AlertUtil.alert("下载已暂停,请检查网络连接!", mContext);
break;
case DownloadManager.PAUSED_WAITING_TO_RETRY:
//the download is paused because some network error occurred and the download manager is waiting before retrying the request
isNeedDownloadAgain = false;
AlertUtil.alert("下载已暂停,正在等待重试!", mContext);
break;
}
break;
case DownloadManager.STATUS_PENDING:
//the download is waiting to start
isNeedDownloadAgain = false;
AlertUtil.alert("更新正在下载!", mContext);
break;
case DownloadManager.STATUS_RUNNING:
//the download is currently running
isNeedDownloadAgain = false;
AlertUtil.alert("更新正在下载!", mContext);
break;
case DownloadManager.STATUS_SUCCESSFUL:
//the download has successfully completed
//isNeedDownloadAgain = false;
if (TextUtils.isEmpty(GlobalContext.mFolderName)) {
GlobalContext.mFolderName = "<span style="font-family: Arial, Helvetica, sans-serif;">XXXX</span>";
}
String fileName = Environment.getExternalStoragePublicDirectory(GlobalContext.mFolderName).getAbsolutePath() + File.separator + "XXXX.apk";
File apkfile = new File(fileName);
if (!apkfile.exists()) {
//apk文件不存在,则重新下载
isNeedDownloadAgain = true;
} else {
isNeedDownloadAgain = false;
installApk(id, downloadManager, mContext);
}
break;
}
}
return isNeedDownloadAgain;
}
9、还有一个问题就是如果下载链接出错时的容错,此问题根据自己情况做不同处理吧,就不再贴代码了
1、注册监听器监听下载完成操作时,一定要使用context的registerReceiver而不要用LocalBroadcastManager的registerReceiver,因为此处是调用的系统的下载功能,如果注册的是本地监听器肯定是接受不到“完成信号”的
2、测试安装程序(installApk)时,一定要打包之后测试,否则会报“已经安装不同签名的同包名的应用”