Android开发App自动更新的实现(基于AsyncTask异步下载)
平时再做app开发的过程中,app自动更新的功能必不可少,但是自身又不是专业安卓开发,因此在这个过程踩过很多坑,特此写一篇博客记录下来,以便后面在其他地方也用到这个功能的时候还能顺利的写出来
首先需要在app进入第一个页面加载的过程中检查app版本,决定是否要更新
一 . 我在首页的初始化方法里面new一个检查版本的类,继承AsyncTask,并调用 execute()方法去执行它;
new CheckVersionInfoTask(ChuShiYe_ZhuJieMian_Main.this,true).execute();
二.在CheckVersionInfoTask类里面进行检查更新等操作,先贴出整个类的源码,再作解释
package com.upload;
/**
* Created by cl on 2019/1/18.
*/
import android.app.AlertDialog;
import android.app.ProgressDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.os.AsyncTask;
import android.text.Html;
import android.util.Log;
import com.Common.MyApplication;
import com.szmj.wjlappandroid.R;
import com.tools.PublicMethod;
import com.utils.UtilityVar;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
/**
*
*/
public class CheckVersionInfoTask extends AsyncTask<Void, Integer, JSONObject> implements ProgressUtil.OnProgressChangeListener{
private static final String TAG = "CheckVersionInfoTask";
private ProgressDialog dialog;
private Context mContext;
private boolean mShowProgressDialog;
private static String VERSION_INFO_URL = "";
private static CheckVersionInfoTask checkVersionInfoTask = null;
private JSONObject result = null,data = null;
private ProgressDialog progressDialog = null;
public static CheckVersionInfoTask getCheckVersionInfoTask(){
return checkVersionInfoTask;
}
public CheckVersionInfoTask(Context context, boolean showProgressDialog) {
this.mContext = context;
this.mShowProgressDialog = showProgressDialog;
this.checkVersionInfoTask = this;
}
//初始化显示Dialog
protected void onPreExecute() {
if (mShowProgressDialog) {
dialog = new ProgressDialog(mContext);
dialog.setMessage(mContext.getString(R.string.check_new_version));
dialog.show();
}
}
//在后台任务(子线程)中检查服务器的版本信息
@Override
protected JSONObject doInBackground(Void... params) {
String banen = AppUtils.getVersionName(MyApplication.getContext());
String b = banen.substring(banen.indexOf(".")-1,banen.length());
VERSION_INFO_URL = UtilityVar.Url_MES + "Login/mesupdate?banben=" + b;
return getVersionInfo(VERSION_INFO_URL);
}
//重写的进度回调方法,current为当前下载进度
@Override
public void onProgressChange(int current) {
//将下载进度发送给进度跟新的方法onProgressUpdate,更新ui
publishProgress(current);
}
//更行当前进度ui
@Override
protected void onProgressUpdate(Integer... value){
Log.e("value",value[0].intValue()+"");
//显示进度条
showProgressDialog(value);
}
//后台任务执行完毕后,解除Dialog并且解析return返回的结果
@Override
protected void onPostExecute(JSONObject result) {
if (dialog != null && dialog.isShowing()) {
dialog.dismiss();
}
if (result != null) {
parseJson(result);
}
}
/**
* 从服务器取得版本信息
* @return
*/
public JSONObject getVersionInfo(String urlStr){
try {
// 新建一个URL对象
URL url = new URL(urlStr);
// 打开一个HttpURLConnection连接
HttpURLConnection urlConn = (HttpURLConnection) url.openConnection();
// 设置连接主机超时时间
urlConn.setConnectTimeout(5 * 1000);
//设置从主机读取数据超时
urlConn.setReadTimeout(5 * 1000);
// 设置是否使用缓存 默认是true
urlConn.setUseCaches(true);
// 设置为Post请求
urlConn.setRequestMethod("GET");
//urlConn设置请求头信息
//设置请求中的媒体类型信息。
urlConn.setRequestProperty("Content-Type", "application/json");
//设置客户端与服务连接类型
urlConn.addRequestProperty("Connection", "Keep-Alive");
// 开始连接
urlConn.connect();
// 判断请求是否成功
if (urlConn.getResponseCode() == 200) {
// 获取返回的数据
String res = streamToString(urlConn.getInputStream());
result = new JSONObject(res);
if( (boolean)result.get("status") ){
data = result.getJSONObject("datas");
}
Log.e(TAG, "Get方式请求成功,result--->" + res);
} else {
Log.e(TAG, "Get方式请求失败");
PublicMethod.showToast(mContext,"网络错误!请稍后再试");
}
// 关闭连接
urlConn.disconnect();
} catch (Exception e) {
e.printStackTrace();
}
return data;
}
/**
*
* @param result
*/
private void parseJson(JSONObject result) {
try {
String apkUrl = result.getString("apkUrl");//APK下载路径
JSONArray arr = result.getJSONArray("texing");//新特性
//对更新的特新信息进行处理
String updateMessage = "";
for(int i = 0; i < arr.length() ; i++){
String s;
if( i == arr.length() -1 ){
s = "["+ (i+1) +"]" +arr.getString(i);
} else {
s = "["+ (i+1) +"]" +arr.getString(i) + "<br/>";
}
updateMessage += s;
}
showDialog(updateMessage, apkUrl);
} catch (JSONException e) {
Log.e(TAG, "parse json error");
}
}
/**
* 显示对话框提示用户有新版本,并且让用户选择是否更新版本
* @param content
* @param downloadUrl
*/
public void showDialog(String content, final String downloadUrl) {
AlertDialog.Builder builder = new AlertDialog.Builder(mContext);
builder.setTitle(R.string.dialog_choose_update_title);
builder.setMessage(Html.fromHtml(content))
.setPositiveButton(R.string.dialog_btn_confirm_download, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
//下载apk文件
goToDownloadApk(downloadUrl);
}
})
.setNegativeButton(R.string.dialog_btn_cancel_download, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
}
});
AlertDialog dialog = builder.create();
//点击对话框外面,对话框不消失
dialog.setCanceledOnTouchOutside(false);
dialog.show();
}
/**
* 显示下载进度条
* @param
*
*/
private void showProgressDialog(Integer... value) {
if( progressDialog == null){
progressDialog = new ProgressDialog(mContext);
}
progressDialog.setTitle("温馨提示");
progressDialog.setMessage("正在下载...");
progressDialog.setProgressStyle(progressDialog.STYLE_HORIZONTAL);
progressDialog.setProgress(0);
progressDialog.incrementProgressBy(value[0].intValue());
if(value != null || value.length != 0){
progressDialog.show();
}
if(value[0].intValue() >= 100){
progressDialog.dismiss();
}
}
/**
* 用intent启用DownloadService服务去下载AKP文件
* @param downloadUrl
*/
private void goToDownloadApk(String downloadUrl) {
Intent intent = new Intent(mContext, DownloadApkService.class);
intent.putExtra("apkUrl", downloadUrl);
mContext.startService(intent);
}
/**
* 将输入流转换成字符串
*
* @param is 从网络获取的输入流
* @return
*/
public String streamToString(InputStream is) {
try {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
byte[] buffer = new byte[1024];
int len = 0;
while ((len = is.read(buffer)) != -1) {
baos.write(buffer, 0, len);
}
baos.close();
is.close();
byte[] byteArray = baos.toByteArray();
return new String(byteArray);
} catch (Exception e) {
Log.e(TAG, e.toString());
return null;
}
}
}
1.在构造方法中,将当前的context对象传进来,后面的布尔值用于检查更新时候的转圈动画显示,若为true则显示new一个Progressdialog用于显示检查更新的转圈动画,同时将自身对象保存在对象的的一个变量中,这个对象在后面的进度条需要用到
public CheckVersionInfoTask(Context context, boolean showProgressDialog) {
this.mContext = context;
this.mShowProgressDialog = showProgressDialog;
this.checkVersionInfoTask = this;
}
//初始化显示Dialog,继承AsyncTask重写的方法,是在异步任务执行之前执行
//可以理解为,new了这个类就执行,根据状态,决定是否显示这个转圈检查更新的ProgressDialog
@Override
protected void onPreExecute() {
if (mShowProgressDialog) {
dialog = new ProgressDialog(mContext);
dialog.setMessage(mContext.getString(R.string.check_new_version));
dialog.show();
}
}
2.然后是异步的请求服务器,获取更新信息
此处还有一个小问题,app版本号只能为整数,若只用这个版本号的话,后期版本更新太多,数据维护将非常麻烦,很容易出错,这里用VersionName比较合适,我的格式为1.0.0,VersionCode只做app内部用于更新的数据,因此我这个取出VersionName并取出其中的版本号,带着这个数据请求后台
//在后台任务(子线程)中检查服务器的版本信息
//该方法是继承AsyncTask重写的方法,相当于是开启一个线程在后台执行任务
//我此处的做法是将app更新的版本信息和更新的地址放在数据库去维护
//每次将当前app更新的版本号带过去请求后台,若版本号大于数据库维护的版本号
//则将版本特性和app更新地址返回
@Override
protected JSONObject doInBackground(Void... params) {
String banen = AppUtils.getVersionName(MyApplication.getContext());
String b = banen.substring(banen.indexOf(".")-1,banen.length());
VERSION_INFO_URL = UtilityVar.Url_MES + "Login/mesupdate?banben=" + b;
return getVersionInfo(VERSION_INFO_URL);
}
/**
* 从服务器取得版本信息
* @return
*/
public JSONObject getVersionInfo(String urlStr){
try {
// 新建一个URL对象
URL url = new URL(urlStr);
// 打开一个HttpURLConnection连接
HttpURLConnection urlConn = (HttpURLConnection) url.openConnection();
// 设置连接主机超时时间
urlConn.setConnectTimeout(5 * 1000);
//设置从主机读取数据超时
urlConn.setReadTimeout(5 * 1000);
// 设置是否使用缓存 默认是true
urlConn.setUseCaches(true);
// 设置为Post请求
urlConn.setRequestMethod("GET");
//urlConn设置请求头信息
//设置请求中的媒体类型信息。
urlConn.setRequestProperty("Content-Type", "application/json");
//设置客户端与服务连接类型
urlConn.addRequestProperty("Connection", "Keep-Alive");
// 开始连接
urlConn.connect();
// 判断请求是否成功
if (urlConn.getResponseCode() == 200) {
// 获取返回的数据
String res = streamToString(urlConn.getInputStream());
result = new JSONObject(res);
if( (boolean)result.get("status") ){
data = result.getJSONObject("datas");
}
Log.e(TAG, "Get方式请求成功,result--->" + res);
} else {
Log.e(TAG, "Get方式请求失败");
PublicMethod.showToast(mContext,"网络错误!请稍后再试");
}
// 关闭连接
urlConn.disconnect();
} catch (Exception e) {
e.printStackTrace();
}
return data;
}
3.doInBackground方法执行完毕会按照定义的返回类型返回从后台获取的数据类型,我这里是json对象,那么此方法执行完毕,会执行onPostExecute方法,并将之前返回的数据将做参数传入
//后台任务执行完毕后,解除Dialog并且解析return返回的结果
//此方法是继承AsyncTask重写的方法,在doInBackground执行完毕执行,并将其返回结果当作参数
//此处将之前的检查更新动画隐藏
@Override
protected void onPostExecute(JSONObject result) {
if (dialog != null && dialog.isShowing()) {
dialog.dismiss();
}
if (result != null) {
parseJson(result);
}
}
/**
*
* @param result
*/
//这个将json数据作一定的处理,具体处理方式,根据自己的json数据来看
private void parseJson(JSONObject result) {
try {
String apkUrl = result.getString("apkUrl");//APK下载路径
JSONArray arr = result.getJSONArray("texing");//新特性
//对更新的特新信息进行处理
String updateMessage = "";
for(int i = 0; i < arr.length() ; i++){
String s;
if( i == arr.length() -1 ){
s = "["+ (i+1) +"]" +arr.getString(i);
} else {
s = "["+ (i+1) +"]" +arr.getString(i) + "<br/>";
}
updateMessage += s;
}
showDialog(updateMessage, apkUrl);
} catch (JSONException e) {
Log.e(TAG, "parse json error");
}
}
/**
* 显示对话框提示用户有新版本,并且让用户选择是否更新版本
* @param content
* @param downloadUrl
*/
public void showDialog(String content, final String downloadUrl) {
AlertDialog.Builder builder = new AlertDialog.Builder(mContext);
builder.setTitle(R.string.dialog_choose_update_title);
builder.setMessage(Html.fromHtml(content))
.setPositiveButton(R.string.dialog_btn_confirm_download, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
//下载apk文件
goToDownloadApk(downloadUrl);
}
})
.setNegativeButton(R.string.dialog_btn_cancel_download, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
}
});
AlertDialog dialog = builder.create();
//点击对话框外面,对话框不消失
dialog.setCanceledOnTouchOutside(false);
dialog.show();
}
/**
* 用intent启用DownloadService服务去下载AKP文件
* @param downloadUrl
*/
private void goToDownloadApk(String downloadUrl) {
Intent intent = new Intent(mContext, DownloadApkService.class);
intent.putExtra("apkUrl", downloadUrl);
mContext.startService(intent);
}
三.至此,更新只完成了前面一部分,后面是调用服务下载apk,用intent启动服务下载,下面是完整的服务代码
package com.upload;
import android.app.IntentService;
import android.app.NotificationManager;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.os.Build;
import android.support.v4.app.NotificationCompat;
import android.support.v4.content.FileProvider;
import android.util.Log;
import com.szmj.wjlappandroid.BuildConfig;
import com.Common.MyApplication;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
/**
* Created by cl on 2019/1/18.
*/
public class DownloadApkService extends IntentService {
private static final int BUFFER_SIZE = 1024 * 1024; //缓存大小
private static final String TAG = "DownloadApkService";
private static final int NOTIFICATION_ID = 0;
private NotificationManager mNotifyManager;
private NotificationCompat.Builder mBuilder;
private ProgressUtil.OnProgressChangeListener progressListener = null;
public DownloadApkService() {
super("DownloadService");
}
/**
* 在onHandleIntent中下载apk文件
* @param intent
*/
@Override
protected void onHandleIntent(Intent intent) {
progressListener = CheckVersionInfoTask.getCheckVersionInfoTask();
//初始化通知,用于显示下载进度
mNotifyManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
mBuilder = new NotificationCompat.Builder(this);
String urlStr = intent.getStringExtra("apkUrl"); //从intent中取得apk下载路径
InputStream in = null;
FileOutputStream out = null;
try {
//建立下载连接
URL url = new URL(urlStr);
HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();
urlConnection.setRequestMethod("GET");
urlConnection.setDoOutput(false);
urlConnection.setConnectTimeout(10 * 1000);
urlConnection.setReadTimeout(10 * 1000);
urlConnection.setRequestProperty("Connection", "Keep-Alive");
urlConnection.setRequestProperty("Charset", "UTF-8");
urlConnection.setRequestProperty("Accept-Encoding", "gzip, deflate");
urlConnection.connect();
//以文件流读取数据
long bytetotal = urlConnection.getContentLength(); //取得文件长度
long bytesum = 0;
int byteread = 0;
in = urlConnection.getInputStream();
File dir = StorageUtils.getCacheDirectory(this); //取得应用缓存目录
//Log.d("缓存地址",dir.getPath());
String apkName = urlStr.substring(urlStr.lastIndexOf("/") + 1, urlStr.length());//取得apK文件名
File apkFile = new File(dir, apkName);
out = new FileOutputStream(apkFile);
byte[] buffer = new byte[BUFFER_SIZE];
int limit = 0;
int oldProgress = 0;
while ((byteread = in.read(buffer)) != -1) {
bytesum += byteread;
out.write(buffer, 0, byteread);
int progress = (int) (bytesum * 100L / bytetotal);
// 如果进度与之前进度相等,则不更新,如果更新太频繁,则会造成界面卡顿
if (progress != oldProgress) {
//进度回调
progressListener.onProgressChange(progress);
}
oldProgress = progress;
}
//卸载原来的apk
/*Uri uri = Uri.fromParts("package", BuildConfig.APPLICATION_ID, null);
Intent intent1 = new Intent(Intent.ACTION_DELETE, uri);
startActivity(intent1);*/
// 下载完成,调用installAPK开始安装文件
installAPk(apkFile);
//Log.d("调试","download apk finish");
mNotifyManager.cancel(NOTIFICATION_ID);
} catch (Exception e) {
Log.e(TAG, "download apk file error");
} finally {
if (out != null) {
try {
out.close();
} catch (IOException ignored) {
}
}
if (in != null) {
try {
in.close();
} catch (IOException ignored) {
}
}
}
}
/**
* 调用系统安装程序安装下载好的apk
* @param apkFile
*/
private void installAPk(File apkFile) {
//Intent intent = new Intent(Intent.ACTION_VIEW);
//如果没有设置SDCard写权限,或者没有sdcard,apk文件保存在内存中,需要授予权限才能安装
try {
// Log.i(TAG, "开始执行安装: ");
Intent intent = new Intent(Intent.ACTION_VIEW);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
//Log.w(TAG, "版本大于 N ,开始使用 fileProvider 进行安装");
intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
Uri contentUri = FileProvider.getUriForFile(
MyApplication.getContext()
, BuildConfig.APPLICATION_ID + ".provider"
, apkFile);
intent.setDataAndType(contentUri, "application/vnd.android.package-archive");
} else {
//Log.w(TAG, "正常进行安装");
intent.setDataAndType(Uri.fromFile(apkFile), "application/vnd.android.package-archive");
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
}
startActivity(intent);
} catch (Exception e) {
Log.e(TAG, e.getMessage());
}
}
}
1). intent启动服务后,在重写的onHandleIntent方法中用io流下载apk,下载完成之后调用安装,该服务的方法没有太多需要解释的地方,需要注意的有两点,一个是下载过程下载进度的显示问题,第二是安装apk的安装目录的权限问题,本人也在此处坑了大概4个小时,最后一步步debug,终于解决了,下面我来一一说明。。
先说第一个下载进度的问题,我这里是在用一个简单的进度提示框来实现,那么问题来了,如何将服务中的进度回调给CheckVersionTask,让其进行ui更新,将进度显示呢。。。
我这个定义了一个工具类,在其中定义一个接口
package com.upload;
/**
* Created by cl on 2019/1/23.
*/
public class ProgressUtil {
public interface OnProgressChangeListener{
void onProgressChange(int val);
}
}
然后再服务类定义一个属性
private ProgressUtil.OnProgressChangeListener progressListener = null;
在onHandleIntent方法中获取
progressListener = CheckVersionInfoTask.getCheckVersionInfoTask();
此处有没有一点熟悉,这个方法就是之前的类CheckVersionInfoTask中的一个方法,我将部分代码贴出来加以说明,将该类实现该接口,并定义一个静态方法获取它本身,那么在服务中,用该接口获取进度,在CheckVersionInfoTask实现该方法就可以获取下载进度了
public class CheckVersionInfoTask extends AsyncTask<Void, Integer, JSONObject> implements ProgressUtil.OnProgressChangeListener{
public static CheckVersionInfoTask getCheckVersionInfoTask(){
return checkVersionInfoTask;
}
public CheckVersionInfoTask(Context context, boolean showProgressDialog) {
this.mContext = context;
this.mShowProgressDialog = showProgressDialog;
this.checkVersionInfoTask = this;
}
}
在DownloadApkService中用该接口接收进度
while ((byteread = in.read(buffer)) != -1) {
bytesum += byteread;
out.write(buffer, 0, byteread);
int progress = (int) (bytesum * 100L / bytetotal);
// 如果进度与之前进度相等,则不更新,如果更新太频繁,则会造成界面卡顿
if (progress != oldProgress) {
//进度回调
progressListener.onProgressChange(progress);
}
oldProgress = progress;
}
那么在CheckVersionInfoTask实现该接口的重写方法中,获取下载进度,其中publishProgress方法是doInBackground将进度发送给onProgressUpdate的方法
//重写的进度回调方法,current为当前下载进度
//实现ProgressUtil.OnProgressChangeListener接口重写的方法,用于获取当前下载进度
@Override
public void onProgressChange(int current) {
//将下载进度发送给进度跟新的方法onProgressUpdate,更新ui
publishProgress(current);
}
//更行当前进度ui
//继承AsyncTask重写的方法,用于进度更新
@Override
protected void onProgressUpdate(Integer... value){
Log.e("value",value[0].intValue()+"");
//显示进度条
showProgressDialog(value);
}
/**
* 显示下载进度条
* @param
*
*/
private void showProgressDialog(Integer... value) {
if( progressDialog == null){
progressDialog = new ProgressDialog(mContext);
}
progressDialog.setTitle("温馨提示");
progressDialog.setMessage("正在下载...");
progressDialog.setProgressStyle(progressDialog.STYLE_HORIZONTAL);
progressDialog.setProgress(0);
progressDialog.incrementProgressBy(value[0].intValue());
if(value != null || value.length != 0){
progressDialog.show();
}
if(value[0].intValue() >= 100){
progressDialog.dismiss();
}
}
第二个问题就是apk的安装啦,这里主要有几个地方需要正确配置
1.主配置文件的provider以及若干权限,authortites为自定义的安装目录,一般设置为包名,在安装的方法里需要和这个保持一致,一般可以这样写,如图:
<provider
android:name="android.support.v4.content.FileProvider"
android:authorities="${applicationId}.provider"
android:grantUriPermissions="true"
android:exported="false">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/file_paths"/>
</provider>
<uses-permission android:name="android.permission.DOWNLOAD_WITHOUT_NOTIFICATION" />
<uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
Uri contentUri = FileProvider.getUriForFile(
MyApplication.getContext()
, BuildConfig.APPLICATION_ID + ".provider"
, apkFile);
2.主配置文件的xml文件配置,新建xml文件夹,如上显示,新建xml文件
第一个路径为内置sd卡的路径配置
第二个路径为外置sd卡的路径配置
第三个路径为全路径,这个一定要配,不然程序会找不到你下载的apk的缓存文件
<?xml version="1.0" encoding="utf-8"?>
<paths>
<external-path path="Android/data/local/tmp/你的包名" name="files_root"/>
<external-path path="." name="external_storage_root"/>
<root-path path="" name ="name"/>
</paths>
再贴一个工具类
package com.upload;
import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.graphics.Bitmap;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
/**
* Created by cl on 2019/1/22.
* 跟App相关的辅助类
*/
public class AppUtils {
/**
* 获取应用程序名称
*/
public static synchronized String getAppName(Context context) {
try {
PackageManager packageManager = context.getPackageManager();
PackageInfo packageInfo = packageManager.getPackageInfo(
context.getPackageName(), 0);
int labelRes = packageInfo.applicationInfo.labelRes;
return context.getResources().getString(labelRes);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
/**
* [获取应用程序版本名称信息]
* @param context
* @return 当前应用的版本名称
*/
public static synchronized String getVersionName(Context context) {
try {
PackageManager packageManager = context.getPackageManager();
PackageInfo packageInfo = packageManager.getPackageInfo(
context.getPackageName(), 0);
return packageInfo.versionName;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
/**
* [获取应用程序版本名称信息]
* @param context
* @return 当前应用的版本号
*/
public static synchronized int getVersionCode(Context context) {
try {
PackageManager packageManager = context.getPackageManager();
PackageInfo packageInfo = packageManager.getPackageInfo(
context.getPackageName(), 0);
return packageInfo.versionCode;
} catch (Exception e) {
e.printStackTrace();
}
return 0;
}
/**
* [获取应用程序版本名称信息]
* @param context
* @return 当前应用的包名
*/
public static synchronized String getPackageName(Context context) {
try {
PackageManager packageManager = context.getPackageManager();
PackageInfo packageInfo = packageManager.getPackageInfo(
context.getPackageName(), 0);
return packageInfo.packageName;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
/**
* 获取图标 bitmap
* @param context
*/
public static synchronized Bitmap getBitmap(Context context) {
PackageManager packageManager = null;
ApplicationInfo applicationInfo = null;
try {
packageManager = context.getApplicationContext()
.getPackageManager();
applicationInfo = packageManager.getApplicationInfo(
context.getPackageName(), 0);
} catch (PackageManager.NameNotFoundException e) {
applicationInfo = null;
}
Drawable d = packageManager.getApplicationIcon(applicationInfo); //xxx根据自己的情况获取drawable
BitmapDrawable bd = (BitmapDrawable) d;
Bitmap bm = bd.getBitmap();
return bm;
}
}
至此,app的下载功能已经全部完成了。。。整个代码基本都是从网上半copy半改完成的,也算是自己的一个进步