轻松实现APP自动检测更新
2016-08-24 02:07
423 查看
概述:为了以快速并且节约的方式让APP更新版本,通常需要在APP内增加自动检测更新新版本的功能。
运行截图:
![](https://img-blog.csdn.net/20160824020123832?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center)
![](https://img-blog.csdn.net/20160824020142051?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center)
![](https://img-blog.csdn.net/20160824020158708?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center)
![](https://img-blog.csdn.net/20160824020412835?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center)
实现:4个步骤
![](https://img-blog.csdn.net/20160824015912360?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center)
1.在服务端放置存储版本信息的文件
一般以json格式保存必要的信息:apk文件下载地址、版本号、更新内容
2.继承AsyncTask创建一个异步任务去下载版本信息文件
从服务器取得版本信息,与本地apk对比版本号,判断是否有更新,若有,则以Dialog让用户选择是否更新,若用户选择更新,则调用服务去完成apk文件的下载
CheckVersionInfoTask.java
注:其中用到的 StorageUtils.getCacheDirectory(context) 是用于取得应用在手机缓存目录
StorageUtils.java
3.创建服务(Service)完成apk文件的下载,下载完成后调用系统的安装程序完成安装
DownloadApkService.java
4.最后一步,new并execute我们写好的异步任务就行了。
new CheckVersionInfoTask(MainActivity.this, true).execute();
注:记得在AndroidManifest.xml中生明权限及注册Service哦
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
本案例完整源码:https://github.com/crazyfzw/AppAutoCheckUpdate
用到的相关知识:
异步任务AsysTask的相关用法:郭霖的Android AsyncTask完全解析,带你从源码的角度彻底理解
自动启动线程执行耗时任务并会自动停止的服务 IntentService的用法:Android理解:IntentService
转载请注明出处:http://blog.csdn.net/fzw_faith/article/details/52296037
运行截图:
实现:4个步骤
1.在服务端放置存储版本信息的文件
一般以json格式保存必要的信息:apk文件下载地址、版本号、更新内容
{ "url":"http://crazyfzw.github.io/demo/auto-update-version/new-version-v2.0.apk", "versionCode":2, "updateMessage":"[1]新增视频弹幕功能<br/>[2]优化离线缓存功能<br/>[3]增强了稳定性" }
2.继承AsyncTask创建一个异步任务去下载版本信息文件
从服务器取得版本信息,与本地apk对比版本号,判断是否有更新,若有,则以Dialog让用户选择是否更新,若用户选择更新,则调用服务去完成apk文件的下载
CheckVersionInfoTask.java
/**
*
*/
public class CheckVersionInfoTask extends AsyncTask<Void, Void, String> {
private static final String TAG = "CheckVersionInfoTask";
private ProgressDialog dialog;
private Context mContext;
private boolean mShowProgressDialog;
private static final String VERSION_INFO_URL = "http://crazyfzw.github.io/demo/auto-update-version/update.json";
public CheckVersionInfoTask(Context context, boolean showProgressDialog) {
this.mContext = context;
this.mShowProgressDialog = showProgressDialog;
}
//初始化显示Dialog
protected void onPreExecute() {
if (mShowProgressDialog) {
dialog = new ProgressDialog(mContext);
dialog.setMessage(mContext.getString(R.string.check_new_version));
dialog.show();
}
}
//在后台任务(子线程)中检查服务器的版本信息
@Override
protected String doInBackground(Void... params) {
return getVersionInfo(VERSION_INFO_URL);
}
//后台任务执行完毕后,解除Dialog并且解析return返回的结果
@Override
protected void onPostExecute(String result) {
if (dialog != null && dialog.isShowing()) {
dialog.dismiss();
}
if (!TextUtils.isEmpty(result)) {
parseJson(result);
}
}
/**
* 从服务器取得版本信息
* { "url":"http://crazyfzw.github.io/demo/auto-update-version/new-version-v2.0.apk", "versionCode":2, "updateMessage":"[1]新增视频弹幕功能<br/>[2]优化离线缓存功能<br/>[3]增强了稳定性" }
* @return
*/
public String getVersionInfo(String urlStr){
HttpURLConnection uRLConnection = null;
InputStream is = null;
BufferedReader buffer = null;
String result = null;
try {
URL url = new URL(urlStr);
uRLConnection = (HttpURLConnection) url.openConnection();
uRLConnection.setRequestMethod("GET");
is = uRLConnection.getInputStream();
buffer = new BufferedReader(new InputStreamReader(is));
StringBuilder strBuilder = new StringBuilder();
String line;
while ((line = buffer.readLine()) != null) {
strBuilder.append(line);
}
result = strBuilder.toString();
} catch (Exception e) {
Log.e(TAG, "http post error");
} finally {
if (buffer != null) {
try {
buffer.close();
} catch (IOException ignored) {
}
}
if (is != null) {
try {
is.close();
} catch (IOException ignored) {
}
}
if (uRLConnection != null) {
uRLConnection.disconnect();
}
}
return result;
}
/**
*
* @param result
*/
private void parseJson(String result) {
try {
JSONObject obj = new JSONObject(result);
String apkUrl = obj.getString("url"); //APK下载路径
String updateMessage = obj.getString("updateMessage");//版本更新说明
int apkCode = obj.getInt("versionCode"); //新版APK对于的版本号
//取得已经安装在手机的APP的版本号 versionCode
int versionCode = getCurrentVersionCode();
//对比版本号判断是否需要更新
if (apkCode > versionCode) {
showDialog(updateMessage, apkUrl);
} else if (mShowProgressDialog) {
Toast.makeText(mContext, mContext.getString(R.string.there_no_new_version), Toast.LENGTH_SHORT).show();
}
} catch (JSONException e) {
Log.e(TAG, "parse json error");
}
}
/**
* 取得当前版本号
* @return
*/
public int getCurrentVersionCode() {
try {
return mContext.getPackageManager().getPackageInfo(mContext.getPackageName(), 0).versionCode;
} catch (PackageManager.NameNotFoundException ignored) {
}
return 0;
}
/**
* 显示对话框提示用户有新版本,并且让用户选择是否更新版本
* @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);
}
}
注:其中用到的 StorageUtils.getCacheDirectory(context) 是用于取得应用在手机缓存目录
StorageUtils.java
final class StorageUtils { private static final String TAG = "StorageUtils"; private static final String EXTERNAL_STORAGE_PERMISSION = "android.permission.WRITE_EXTERNAL_STORAGE"; private StorageUtils() { } /** * Returns application cache directory. Cache directory will be created on SD card * ("/Android/data/[app_package_name]/cache") if card is mounted and app has appropriate permission. Else - * Android defines cache directory on device's file system. */ public static File getCacheDirectory(Context context) { File appCacheDir = null; if (MEDIA_MOUNTED.equals(Environment.getExternalStorageState()) && hasExternalStoragePermission(context)) { appCacheDir = getExternalCacheDir(context); } if (appCacheDir == null) { appCacheDir = context.getCacheDir(); } if (appCacheDir == null) { Log.w(TAG, "Can't define system cache directory! The app should be re-installed."); } return appCacheDir; } private static File getExternalCacheDir(Context context) { File dataDir = new File(new File(Environment.getExternalStorageDirectory(), "Android"), "data"); File appCacheDir = new File(new File(dataDir, context.getPackageName()), "cache"); if (!appCacheDir.exists()) { if (!appCacheDir.mkdirs()) { Log.w(TAG, "Unable to create external cache directory"); return null; } try { new File(appCacheDir, ".nomedia").createNewFile(); } catch (IOException e) { Log.i(TAG, "Can't create \".nomedia\" file in application external cache directory"); } } return appCacheDir; } private static boolean hasExternalStoragePermission(Context context) { int perm = context.checkCallingOrSelfPermission(EXTERNAL_STORAGE_PERMISSION); return perm == PackageManager.PERMISSION_GRANTED; } }
3.创建服务(Service)完成apk文件的下载,下载完成后调用系统的安装程序完成安装
DownloadApkService.java
public class DownloadApkService extends IntentService{ private static final int BUFFER_SIZE = 10 * 1024; //缓存大小 private static final String TAG = "DownloadService"; private static final int NOTIFICATION_ID = 0; private NotificationManager mNotifyManager; private NotificationCompat.Builder mBuilder; public DownloadApkService() { super("DownloadApkService"); } /** * 在onHandleIntent中下载apk文件 * @param intent */ @Override protected void onHandleIntent(Intent intent) { //初始化通知,用于显示下载进度 mNotifyManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE); mBuilder = new NotificationCompat.Builder(this); String appName = getString(getApplicationInfo().labelRes); int icon = getApplicationInfo().icon; mBuilder.setContentTitle(appName).setSmallIcon(icon); 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); //取得应用缓存目录 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) { updateProgress(progress); } oldProgress = progress; } // 下载完成,调用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) { } } } } /** * 实时更新下载进度条显示 * @param progress */ private void updateProgress(int progress) { //"正在下载:" + progress + "%" mBuilder.setContentText(this.getString(R.string.dialog_choose_update_content, progress)).setProgress(100, progress, false); PendingIntent pendingintent = PendingIntent.getActivity(this, 0, new Intent(), PendingIntent.FLAG_CANCEL_CURRENT); mBuilder.setContentIntent(pendingintent); mNotifyManager.notify(NOTIFICATION_ID, mBuilder.build()); } /** * 调用系统安装程序安装下载好的apk * @param apkFile */ private void installAPk(File apkFile) { Intent intent = new Intent(Intent.ACTION_VIEW); //如果没有设置SDCard写权限,或者没有sdcard,apk文件保存在内存中,需要授予权限才能安装 try { String[] command = {"chmod", "777", apkFile.toString()}; //777代表权限 rwxrwxrwx ProcessBuilder builder = new ProcessBuilder(command); builder.start(); } catch (IOException ignored) { } intent.setDataAndType(Uri.fromFile(apkFile), "application/vnd.android.package-archive"); intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); startActivity(intent); } }
4.最后一步,new并execute我们写好的异步任务就行了。
new CheckVersionInfoTask(MainActivity.this, true).execute();
注:记得在AndroidManifest.xml中生明权限及注册Service哦
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
本案例完整源码:https://github.com/crazyfzw/AppAutoCheckUpdate
用到的相关知识:
异步任务AsysTask的相关用法:郭霖的Android AsyncTask完全解析,带你从源码的角度彻底理解
自动启动线程执行耗时任务并会自动停止的服务 IntentService的用法:Android理解:IntentService
转载请注明出处:http://blog.csdn.net/fzw_faith/article/details/52296037
相关文章推荐
- iOS 开发笔记 - 开发中如何实现自动检测更新APP
- 求助!!用vue做了一款app,怎么实现打开app自动检测下载更新的功能呢
- IOS开发中如何实现自动检测更新APP
- iOS 开发笔记 - 开发中如何实现自动检测更新APP
- iOS程序自动检测更新的实现
- iOS程序自动检测更新的实现
- 【iOS】APP实现检测更新
- iOS程序自动检测更新的实现
- iOS程序自动检测更新的实现
- 简单实现安卓app自动更新功能
- Android 轻松实现后台搭建+APP版本更新
- H5app自动更新思路与实现
- Android 轻松实现后台搭建+APP版本更新
- 如何实现已发布app的自动更新
- Android 轻松实现后台搭建+APP版本更新
- Android 轻松实现后台搭建+APP版本更新
- github提供的第三方库实现APP自动更新
- Android App自动检测更新--时间随机
- Delphi XE8 利用HttpClient实现的一个App自动更新组件
- Android实现APP自动更新功能