认真查看第八项
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); } } } }
/** * 安装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()); }
/** * 卸载应用程序 */ 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; }
1、注册监听器监听下载完成操作时,一定要使用context的registerReceiver而不要用LocalBroadcastManager的registerReceiver,因为此处是调用的系统的下载功能,如果注册的是本地监听器肯定是接受不到“完成信号”的
2、测试安装程序(installApk)时,一定要打包之后测试,否则会报“已经安装不同签名的同包名的应用”