Android App更新模块
来源:互联网 发布:数据集成 编辑:程序博客网 时间:2024/05/18 00:57
应用更新有两种:
1、 检测到更新,App实现下载功能,下载安装。
2、检查到更新,跳转应用市场下载。- 两种方法优缺点:
第一种:
- 两种方法优缺点:
- 优点:是,下载同意,便于版本同意升级,只要用户点击更新,可以保证其实官方最新的包。
缺点:实现起来稍微优点麻烦,如果写不好,下载的包可能无法解析,有些机型导致下载了无法安装的问题。
第二种:
- 优点:实现简单,几乎不用写几行代码。
- 缺点:每个手机安装的应用市场不同,不同应用市场的审核速度不一样,导致用户用的版本参差不齐,提示更新后,用户去应用市场下载安装,发现还提示更新,是因为应用市场上不是最新包。
下面先给出第二种实习方法,再给第一种方法(实践后结论下载稳定)
//检查到需要更新,调用 ToolUtil.gotoMarket(mActivity, mActivity.getPackageName());
/** * 打开市场 */ public static void gotoMarket(Context context, String pck) { if (!isHaveMarket(context)) { Toast.makeText(context, "您手机中没有安装应用市场!", Toast.LENGTH_SHORT).show(); return; } Intent intent = new Intent(); intent.setAction(Intent.ACTION_VIEW); intent.setData(Uri.parse("market://details?id=" + pck)); if (intent.resolveActivity(context.getPackageManager()) != null) { context.startActivity(intent); } }
/** * 是否安装市场 */ private static boolean isHaveMarket(Context context) { Intent intent = new Intent(); intent.setAction("android.intent.action.MAIN"); intent.addCategory("android.intent.category.APP_MARKET"); PackageManager pm = context.getPackageManager(); List<ResolveInfo> infos = pm.queryIntentActivities(intent, 0); return infos.size() > 0; }
第二种到此就完了。可以验证下,前题是,你的app要在应用商场上线。没有上线的话,是找不到对应的APP的。
那么下来重点说下第一种:
先看效果图:
这里先说,途中的dialog,用的是github上 material-dialogs 。(这了忽略对话框的代码)
从左到右,检查更新-->是否需要下载-->点击下载-->状态栏和对话框同时走下载进度条-->最后下载成功。
- 提出下载的主要代码。
// 启动Service 开始下载AppUpdateService.startUpdate(mContext, url, fileName, new AppUpdateService.OnProgressListener() { @Override public void onProgress(int progress) { //更新对话框进度条 mDialog.setProgress(progress); } @Override public void onSuccess(boolean isSuccess) { mDialog.dismiss(); //失败提示 if (!isSuccess) { ToastTools.toastLong("更新不成功"); } } });
这里用到的InternetService类,IntentService是Service的子类,
IntentService实现了work非阻塞线程,适合做耗时操作,可以自行Google or 百度 他们的区别和用法。
package com.hundun.yanxishe.service;import android.app.IntentService;import android.app.Notification;import android.app.NotificationManager;import android.app.PendingIntent;import android.content.Context;import android.content.Intent;import android.net.Uri;import android.widget.RemoteViews;import com.hundun.yanxishe.R;import com.hundun.yanxishe.tools.LogTool;import java.io.File;import java.io.FileOutputStream;import java.io.InputStream;import java.net.HttpURLConnection;import java.net.URL;/** * An {@link IntentService} subclass for handling asynchronous task requests in * a service on a separate handler thread. * <p> * helper methods. */public class AppUpdateService extends IntentService { private static final String ACTION_UPDATE = "com.hundun.yanxishe.service.action.update"; private static final String EXTRA_URL = "com.hundun.yanxishe.service.extra.url"; private static final String EXTRA_FILE_NAME = "com.hundun.yanxishe.service.extra.file.name"; private boolean isRunning = false; private NotificationManager updateNotificationManager; private Notification updateNotification; private PendingIntent updatePendingIntent; private static OnProgressListener mProgressListener; public interface OnProgressListener { void onProgress(int progress); void onSuccess(boolean isSuccess); } public AppUpdateService() { super("AppUpdateService"); } @Override protected void onHandleIntent(Intent intent) { if (intent != null) { final String action = intent.getAction(); if (ACTION_UPDATE.equals(action)) { final String param1 = intent.getStringExtra(EXTRA_URL); final String param2 = intent.getStringExtra(EXTRA_FILE_NAME); startDownloade(param1, param2); } } } @Override public void onDestroy() { mProgressListener = null; super.onDestroy(); } /** * Starts this service to perform action Baz with the given parameters. If * the service is already performing a task this action will be queued. * * @see IntentService */ public static void startUpdate(Context context, String param1, String param2, OnProgressListener pregressListener) { mProgressListener = pregressListener; Intent intent = new Intent(context, AppUpdateService.class); intent.setAction(ACTION_UPDATE); intent.putExtra(EXTRA_URL, param1); intent.putExtra(EXTRA_FILE_NAME, param2); context.startService(intent); } private void startDownloade(String url, String fileName) { LogTool.debug("开始升级----" + url + "---" + fileName); if (isRunning) { return; } isRunning = true; initRemoteView(); try { boolean isSuccess = downloadUpdateFile(url, fileName); if (mProgressListener != null) { mProgressListener.onSuccess(isSuccess); } if (isSuccess) { Uri uri = Uri.fromFile(new File(fileName)); Intent installIntent = new Intent(Intent.ACTION_VIEW); installIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); installIntent.setDataAndType(uri, "application/vnd.android.package-archive"); startActivity(installIntent); try { updateNotificationManager.cancel(0); } catch (Exception ex) { LogTool.error(ex.getMessage(), ex); } } else { Notification notification = new Notification.Builder(AppUpdateService.this) .setContentTitle(getString(R.string.app_name)) .setContentText("下载失败") .setSmallIcon(R.drawable.download) .build(); updateNotificationManager.notify(0, notification); } } catch (Exception e) { e.printStackTrace(); } } /** * 初始化状态栏进度条 */ private void initRemoteView() { try { updateNotificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE); //状态栏提醒内容 updateNotification = new Notification.Builder(this) .setTicker("版本更新下载") .setWhen(System.currentTimeMillis()) .setSmallIcon(R.drawable.download).build(); updatePendingIntent = PendingIntent.getActivity(this, 0, new Intent(this, RemoteViews.class), 0); updateNotification.contentIntent = updatePendingIntent; //状态栏提醒内容 updateNotification.contentView = new RemoteViews(getApplication().getPackageName(), R.layout.progress); updateNotification.contentView.setProgressBar(R.id.progressBar1, 100, 0, false); updateNotification.contentView.setTextViewText(R.id.textView1, "0%"); // 发出通知 updateNotificationManager.notify(0, updateNotification); } catch (Exception e) { e.printStackTrace(); } } /** * 下载文件 * * @param downloadUrl * @param filepath * @return * @throws Exception */ private boolean downloadUpdateFile(String downloadUrl, String filepath) { try { int downloadCount = 0; int currentSize = 0; long totalSize = 0; int updateTotalSize = 0; boolean result = false; HttpURLConnection httpConnection = null; InputStream is = null; FileOutputStream fos = null; File temp = new File(filepath + ".tmp"); if (temp.getParentFile().isDirectory()) { temp.getParentFile().mkdirs(); } try { URL url = new URL(downloadUrl); httpConnection = (HttpURLConnection) url.openConnection(); httpConnection.setRequestProperty("User-Agent", "PacificHttpClient"); if (currentSize > 0) { httpConnection.setRequestProperty("RANGE", "bytes=" + currentSize + "-"); } httpConnection.setConnectTimeout(20000); httpConnection.setReadTimeout(120000); updateTotalSize = httpConnection.getContentLength(); if (httpConnection.getResponseCode() == 404) { throw new Exception("fail!"); } is = httpConnection.getInputStream(); fos = new FileOutputStream(temp, false); byte buffer[] = new byte[4096]; int readsize = 0; while ((readsize = is.read(buffer)) > 0) { fos.write(buffer, 0, readsize); totalSize += readsize; // 为了防止频繁的通知导致应用吃紧,百分比增加10才通知一次 if ((downloadCount == 0) || (int) (totalSize * 100 / updateTotalSize) - 1 > downloadCount) { downloadCount += 1; try { updateNotification.contentView.setProgressBar(R.id.progressBar1, 100, (int) totalSize * 100 / updateTotalSize, false); updateNotification.contentView.setTextViewText(R.id.textView1, (int) totalSize * 100 / updateTotalSize + "%"); updateNotification.contentIntent = updatePendingIntent; updateNotificationManager.notify(0, updateNotification); if (mProgressListener != null) { mProgressListener.onProgress((int) totalSize * 100 / updateTotalSize); System.out.println("AppUpdateService.downloadUpdateFile"+(int) totalSize * 100 / updateTotalSize); } } catch (Exception ex) { LogTool.error(ex.getMessage(), ex); } } } temp.renameTo(new File(filepath)); temp.delete(); } finally { if (httpConnection != null) { httpConnection.disconnect(); } if (is != null) { is.close(); } if (fos != null) { fos.close(); } result = updateTotalSize > 0 && updateTotalSize == totalSize; if (!result) { //下载失败或者为下载完成 new File(filepath).delete(); } } return result; } catch (Exception e) { e.printStackTrace(); return false; } }}
贴出状态栏的布局文件:
<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" android:gravity="center_vertical" android:orientation="horizontal" > <ImageView android:id="@+id/imageView1" android:layout_width="30dp" android:layout_height="30dp" android:paddingLeft="5dp" android:scaleType="centerInside" android:src="@drawable/download" /> <ProgressBar android:id="@+id/progressBar1" style="?android:attr/progressBarStyleHorizontal" android:layout_width="0dp" android:layout_height="4dp" android:layout_marginLeft="10dp" android:layout_marginRight="5dp" android:layout_weight="1" android:progressDrawable="@drawable/progressbar_style" /> <TextView android:id="@+id/textView1" android:layout_width="40dp" android:layout_height="wrap_content" android:layout_marginLeft="5dp" android:layout_marginRight="5dp" android:text="100%" android:textColor="#888888" android:textSize="14sp"/></LinearLayout>
这里贴代码比较多,没什么讲解,但是如果你对照着每行代码写下来,应该不需要我讲解就会明白了。
核心代码已经全部给出,如有疑问,可以“简书”找 “小追兵”留言。
注意:
状态栏的图片setSmallIcon(R.drawable.download)
,这里的图片不要太大(我的6464 px),还有注意放在drawable文件夹下,否则可能会包异常。改了,如果还报异常,clean项目应该就好了。*
文件从网络下载,写流的部分,不是我写,搬砖搬来的。
文/小追兵(简书作者)
原文链接:http://www.jianshu.com/p/a48707578f55
著作权归作者所有,转载请联系作者获得授权,并标注“简书作者”。
原文链接:http://www.jianshu.com/p/a48707578f55
著作权归作者所有,转载请联系作者获得授权,并标注“简书作者”。
0 0
- Android app更新模块
- Android APP 更新模块
- Android App更新模块
- App更新模块
- Android APP 登陆模块
- Android 更新模块
- Android版本更新模块
- Android App补丁更新
- Android App补丁更新
- 动态更新android app
- Android APP增量更新
- Android App更新功能
- android实现app更新
- android app 版本更新
- Android App 更新
- App更新(Android)
- android App更新
- Android app更新版本
- android studio 提交工程到github
- 面向对象封装--行星旋转案例canvas-konva.js
- CLion v2016.3发布,代码分析改进,UI界面调整
- Git入门笔记
- 流水线公式
- Android App更新模块
- 常用开发工具镜像,不用翻墙,即可下载Chrome Android Studio Gradle Golang NDK SDK NodeJS
- redis - 配置文件详解
- [源码解读] FastClick.js源码解读
- maven创建父子项目
- 如何关闭html上嵌入的iframe的问题
- weex传图
- 【填坑】cannot open makeMtk.ini
- MySQL基础(二)