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
著作权归作者所有,转载请联系作者获得授权,并标注“简书作者”。
0 0
原创粉丝点击