Android 检查更新 下载 安装
2013-10-24 22:38
405 查看
android 自动更新什么的网上一堆,废话不说,直接上代码
首先,用全局数据类保存更新URL(获取服务端版本、apk文件下载),以及文件路径等
然后呢,既然想要检测版本,那么就要有本地安装版本code和服务器端的版本code
在AndroidManifest.xml文件中,versionCode用来识别应用版本code(用来比较大小的,integer),versionName则是给用户看的(string)
那么在MyApplication中提供两个方法,getLocalVersion(获取本地版本code)和 startUpdateService(启动升级服务入口方法)
现在就是重点的UpdateService了
以上用了4个static方法来完成更新下载功能的启动,或者抽出来写在别的地方也可以啦
这个就是通知的布局了
对了,自定义Service一定要在清单文件里的Application节点下注册进去
启动检查的例子:点击检查更新的组件
效果如下
![](https://img-blog.csdn.net/20131024224325281?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvYWx2aW5jZTEyODAyOTcyMjQ=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
![](https://img-blog.csdn.net/20131024224332312?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvYWx2aW5jZTEyODAyOTcyMjQ=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
![](https://img-blog.csdn.net/20131024224338984?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvYWx2aW5jZTEyODAyOTcyMjQ=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
![](https://img-blog.csdn.net/20131024224345125?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvYWx2aW5jZTEyODAyOTcyMjQ=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
首先,用全局数据类保存更新URL(获取服务端版本、apk文件下载),以及文件路径等
public class Global { /* * =================== 版本信息 ================ */ /** * 本地安装版本 */ public static int localVersion = 0; /** * 服务器版本 */ public static int serverVersion = 0; /* * =================== 常量数据 ================= */ /** 服务器url */ public static final String REQUEST_HOST = "http://xxxxxxxx"; /* * 其他数据涉及公司项目,就不写出来了 */ /** 数据存储目录 */ public static final String DATA_PATH = "xxxxx"; /** 升级存储目录 */ public static final String DOWNLOAD_DIR = DATA_PATH + "/download"; /** 更新应用url */ public static final String UPDATE_URL = REQUEST_HOST + "xxxxxx.apk"; /** 检查更新(服务器xml文件链接url) */ public static final String SERVER_VERSION_URL = REQUEST_HOST + "xxxxxx"; // 这里我们用xml保存版本信息 }
然后呢,既然想要检测版本,那么就要有本地安装版本code和服务器端的版本code
在AndroidManifest.xml文件中,versionCode用来识别应用版本code(用来比较大小的,integer),versionName则是给用户看的(string)
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="xxx.xxx.xxx" android:versionCode="1" android:versionName="1.0" >
那么在MyApplication中提供两个方法,getLocalVersion(获取本地版本code)和 startUpdateService(启动升级服务入口方法)
public class MApplication extends Application { @Override public void onCreate() { super.onCreate(); // ...... getLocalVersion(); // 读取版本code } /** * 获取应用版本信息 */ public void getLocalVersion() { try { PackageInfo packageInfo = getApplicationContext().getPackageManager().getPackageInfo(getPackageName(), 0); Global.localVersion = packageInfo.versionCode; } catch (NameNotFoundException e) { e.printStackTrace(); } } }
现在就是重点的UpdateService了
public class UpdateService extends Service { private static final String TAG = "UpdateService"; private static final int TIMEOUT = 5 * 1000; // 超时 private static final int DOWN_OK = 1; private static final int DOWN_ERROR = 0; private String appName; private NotificationManager notificationManager; // 通知管理器 private Notification notification; // 通知 private Intent updateIntent; private PendingIntent pendingIntent; private int notification_id = 1; RemoteViews contentView; @Override public IBinder onBind(Intent arg0) { return null; } @Override public int onStartCommand(Intent intent, int flags, int startId) { appName = intent.getStringExtra("appName"); // 创建文件 FileUtil.createFile(getString(R.string.app_name)); // 这里就是根据应用名在存储目录创建一个appname.apk文件 createNotification(); startUpdate(); return super.onStartCommand(intent, flags, startId); } /*** * 创建通知栏 */ public void createNotification() { /* * 自定义Notification视图 */ contentView = new RemoteViews(getPackageName(), R.layout.notification_item); contentView.setTextViewText(R.id.notificationTitle, appName + "—" +getString(R.string.soft_update_progress)); contentView.setTextViewText(R.id.notificationPercent, "0%"); contentView.setProgressBar(R.id.notificationProgress, 100, 0, false); updateIntent = new Intent(this, MainActivity.class); updateIntent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP); pendingIntent = PendingIntent.getActivity(this, 0, updateIntent, 0); // 初始化通知 notification = new Notification(R.drawable.ic_logo, getString(R.string.soft_down_start) + " " + appName, System.currentTimeMillis()); notification.flags |= Notification.FLAG_NO_CLEAR; notification.defaults |= Notification.DEFAULT_SOUND | Notification.DEFAULT_VIBRATE; // 设置通知铃声和振动提醒 notification.contentView = contentView; notification.contentIntent = pendingIntent; // 发送通知 notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE); notificationManager.notify(notification_id, notification); // 清除通知铃声 notification.defaults = 0; } /*** * 开启线程下载更新 */ public void startUpdate() { final Handler handler = new Handler() { @Override public void handleMessage(Message msg) { // 添加通知声音 notification.defaults |= Notification.DEFAULT_SOUND; switch (msg.what) { case DOWN_OK: // 下载完成,点击安装 Uri uri = Uri.fromFile(FileUtil.updateFile); // 安装应用意图 Intent intent = new Intent(Intent.ACTION_VIEW); intent.setDataAndType(uri, "application/vnd.android.package-archive"); pendingIntent = PendingIntent.getActivity(UpdateService.this, 0, intent, 0); notification.tickerText = appName + " " + getString(R.string.soft_down_complete); notification.setLatestEventInfo(UpdateService.this, appName, getString(R.string.soft_down_ok), pendingIntent); break; case DOWN_ERROR: notification.tickerText = appName + " " + getString(R.string.soft_down_error); notification.setLatestEventInfo(UpdateService.this, appName, getString(R.string.soft_down_error), pendingIntent); } notification.flags = Notification.FLAG_AUTO_CANCEL; notificationManager.notify(notification_id, notification); stopService(updateIntent); stopSelf(); } }; // 启动线程下载更新 new Thread(new Runnable(){ @Override public void run() { try { downloadUpdateFile(Global.UPDATE_URL, FileUtil.updateFile.toString(), handler); } catch (Exception e) { e.printStackTrace(); handler.sendMessage(handler.obtainMessage(DOWN_ERROR)); } } }).start(); } /*** * 下载文件 * * @return * @throws MalformedURLException */ public void downloadUpdateFile(String down_url, String file, Handler handler) throws Exception { int totalSize; // 文件总大小 InputStream inputStream; FileOutputStream outputStream; URL url = new URL(down_url); HttpURLConnection httpURLConnection = (HttpURLConnection) url.openConnection(); httpURLConnection.setConnectTimeout(TIMEOUT); httpURLConnection.setReadTimeout(TIMEOUT); // 获取下载文件的size totalSize = httpURLConnection.getContentLength(); if (httpURLConnection.getResponseCode() == 404) { throw new Exception("fail!"); } inputStream = httpURLConnection.getInputStream(); outputStream = new FileOutputStream(file, false); // 异步任务开始下载 new UpdateAsyncTask(inputStream, outputStream, handler).execute(totalSize); } private class UpdateAsyncTask extends AsyncTask<Integer, Integer, Boolean> { private InputStream in; private FileOutputStream fos; private Handler handler; public UpdateAsyncTask(InputStream inputStream, FileOutputStream outputStream, Handler handler) { super(); in = inputStream; fos = outputStream; this.handler = handler; } @Override protected Boolean doInBackground(Integer... params) { int totalSize = params[0]; // 下载总大小 int downloadCount = 0; // 已下载大小 int updateProgress = 0; // 更新进度 int updateStep = 5; // 更新进度步进 byte buffer[] = new byte[1024]; int readsize = 0; try { while ((readsize = in.read(buffer)) != -1) { fos.write(buffer, 0, readsize); // 计算已下载到的大小 downloadCount += readsize; // 先计算已下载的百分比,然后跟上次比较是否有增加,有则更新通知进度 int now = downloadCount * 100 / totalSize; if (updateProgress < now) { updateProgress = now; Log.d(TAG, "update: " + updateProgress + "%"); publishProgress(updateProgress); } } } catch (Exception e) { Log.d(TAG, "download err===>\n"); e.printStackTrace(); return false; } finally { try { fos.close(); in.close(); } catch (IOException e) { e.printStackTrace(); } } return true; } @Override protected void onProgressUpdate(Integer... values) { int progress = values[0]; // 改变通知栏 contentView.setTextViewText(R.id.notificationPercent, progress + "%"); contentView.setProgressBar(R.id.notificationProgress, 100, progress, false); // show_view notificationManager.notify(notification_id, notification); } @Override protected void onPostExecute(Boolean result) { if (result) { handler.sendMessage(handler.obtainMessage(DOWN_OK)); // 通知handler已经下载完成 } else { handler.sendMessage(handler.obtainMessage(DOWN_ERROR)); // 通知handler下载出错 } super.onPostExecute(result); } } /** * 检查版本信息 */ public static void checkVersion(final Context context, final Handler msgHandler) { final Handler promptHandler = new Handler() { @Override public void handleMessage(Message msg) { new AlertDialog.Builder(context).setTitle("应用升级") .setMessage("发现新版本,要立即更新吗?") .setPositiveButton("更新", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { startUpdateService(context); } }) .setNegativeButton("以后再说", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { dialog.dismiss(); } ).show(); } }; new Thread() { @Override public void run() { getServiceVersion(); if (msgHandler != null) msgHandler.sendMessage(msgHandler.obtainMessage(1)); if (Global.localVersion < Global.serverVersion) { // 提示服务器有新版本,需要更新 promptHandler.sendMessage(promptHandler.obtainMessage(1)); } } }.start(); } /** * 启动升级服务下载升级 */ public static void startUpdateService(Context context) { Intent intent = new Intent(context, UpdateService.class); intent.putExtra("appName", context.getString(R.string.app_name)); context.startService(intent); } /*** * 获取服务器端的serverVersion. */ public static void getServiceVersion() { HttpClient client = new DefaultHttpClient(); HttpGet get = new HttpGet(Global.UPDATE_VERSION_URL); HttpResponse response = null; try { response = client.execute(get); } catch (Exception e) { Log.e(TAG, "get Service Version err==>\n"); e.printStackTrace(); client.getConnectionManager().closeExpiredConnections(); } if (response != null) { if (response.getStatusLine().getStatusCode() == 200) { HttpEntity entity = response.getEntity(); if (entity.isStreaming()) { try { InputStream in = entity.getContent(); Map<String, String> map = parseXml(in); if (map != null) { Global.serverVersion = Integer.parseInt((String) map.get("version")); } } catch (Exception e) { e.printStackTrace(); } } } } } /** * 解析xml数据 * @param in */ public static Map<String, String> parseXml(InputStream in) { // 这里是通过流读取xml文件,然后解析出一个Map出来,当然,这时候我们需要的是 version } }
以上用了4个static方法来完成更新下载功能的启动,或者抽出来写在别的地方也可以啦
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="wrap_content" android:layout_height="wrap_content" android:paddingBottom="5dp" android:paddingLeft="10dp" android:paddingRight="10dp" android:paddingTop="5dp" > <ImageView android:id="@+id/notificationImage" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerVertical="true" android:contentDescription="@null" android:src="@android:drawable/stat_sys_download" /> <TextView android:id="@+id/notificationTitle" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentRight="true" android:layout_marginLeft="3dp" android:layout_toRightOf="@id/notificationImage" android:gravity="left" android:paddingLeft="8dp" android:paddingRight="8dp" android:textColor="#FFFFFF" /> <FrameLayout android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignLeft="@id/notificationTitle" android:layout_alignParentRight="true" android:layout_below="@id/notificationTitle" android:layout_marginTop="3dp" android:paddingLeft="8dp" android:paddingRight="8dp" > <ProgressBar android:id="@+id/notificationProgress" style="?android:attr/progressBarStyleHorizontal" android:layout_width="match_parent" android:layout_height="match_parent" android:paddingLeft="3dp" android:paddingRight="3dp" android:paddingTop="2dp" /> <TextView android:id="@+id/notificationPercent" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" android:textColor="#FFFFFF" /> </FrameLayout> </RelativeLayout>
这个就是通知的布局了
对了,自定义Service一定要在清单文件里的Application节点下注册进去
<service android:name=".service.UpdateService"></service>
启动检查的例子:点击检查更新的组件
public class PreferencesActivity extends Activity { //.............. /* * 检查更新 */ public void checkUpdate(View v) { progressUpdate.setVisibility(0); // 显示进度圈圈 UpdateService.checkVersion(this, new Handler() { @Override public void handleMessage(Message msg) { progressUpdate.setVisibility(View.GONE); // 获取到serverCode后,隐藏进度 } }); } }
效果如下
相关文章推荐
- 介绍一款信息管理系统的开源框架---jeecg
- 聚类算法之kmeans算法java版本
- java实现 PageRank算法
- 解決Linux下Android开发真机调试设备不被识别问题
- PropertyChangeListener简单理解
- [Android]在代码里运行另一个程序的方法
- 插入排序
- 冒泡排序
- 堆排序
- 快速排序
- 二叉查找树
- [原创]java局域网聊天系统
- java很神奇 用swing制作欢迎屏幕
- java自动生成验证码插件-kaptcha
- ITeye上“10个人,8个人不会解释这个问题”的帖子
- Java IO与NIO的一些文件拷贝测试
- Java反射随记
- Java简单字符串插值实现
- String.intern