Android应用更新升级实现

来源:互联网 发布:迪杰斯特拉算法表 编辑:程序博客网 时间:2024/04/28 03:58


Android应用更新升级实现


介绍

在产品的开发中,android升级提示,下载更新是必备的功能,否则等用户被动去官方网,或者第三方商店提示,就为时已晚了。

原理

在用户每次打开应用的时候,都与服务器进行一次交互,获取版本信息,对比之后,如果版本号大于当前版本号,那么就提示用户升级,否则就当什么都没发生。

直接看代码。

实现

 权限

    <uses-permission android:name="android.permission.INTERNET" />    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />

使用起来非常简单

复制代码
    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        AppVersion av = new AppVersion();        av.setApkName("AppUpdate.apk");        av.setSha1("FCDA0D0E1E7D620A75DA02A131E2FFEDC1742AC8");        av.setAppName("博客园");        av.setUrl("http://down.myapp.com/myapp/qqteam/AndroidQQ/mobileqq_android.apk");        av.setContent("1、测试升级;2、测试升级2!!;3、一大波功能!");        av.setVerCode(2);        av.setVersionName("1.1");        AppUpdateUtils.init(MainActivity.this, av, true,false);        AppUpdateUtils.upDate();    }
复制代码

 

自定义消息提示布局,可以弄成自己喜欢的样子。

复制代码
<?xml version="1.0" encoding="utf-8"?><RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"    android:layout_width="fill_parent"    android:layout_height="fill_parent"    android:padding="3dp" >    <ImageView        android:id="@+id/imageView"        android:layout_width="30dp"        android:layout_height="30dp"        android:layout_margin="3dp"        android:src="@drawable/ic_launcher" />    <TextView        android:id="@+id/fileName"        android:layout_width="fill_parent"        android:layout_height="fill_parent"        android:layout_alignBottom="@id/imageView"        android:layout_toRightOf="@id/imageView"        android:gravity="center_vertical"        android:textColor="@android:color/white" />    <TextView        android:id="@+id/rate"        android:layout_width="fill_parent"        android:layout_height="wrap_content"        android:layout_alignRight="@id/imageView"        android:layout_below="@id/imageView"        android:gravity="center"        android:text="0%"        android:textColor="@android:color/white" />    <ProgressBar        android:id="@+id/progress"        style="?android:attr/progressBarStyleHorizontal"        android:layout_width="fill_parent"        android:layout_height="wrap_content"        android:layout_alignLeft="@id/fileName"        android:layout_below="@id/fileName"        android:max="100"        android:progress="0" /></RelativeLayout>
复制代码

核心代码

复制代码
/** * @author Leestar54  * http://www.cnblogs.com/leestar54 */package com.example.appupdate;import java.io.BufferedInputStream;import java.io.File;import java.io.FileInputStream;import java.io.FileOutputStream;import java.io.InputStream;import java.math.BigInteger;import java.net.URL;import java.net.URLConnection;import java.security.MessageDigest;import android.app.AlertDialog;import android.app.Notification;import android.app.NotificationManager;import android.app.PendingIntent;import android.app.ProgressDialog;import android.content.Context;import android.content.DialogInterface;import android.content.DialogInterface.OnCancelListener;import android.content.Intent;import android.content.pm.PackageManager.NameNotFoundException;import android.net.Uri;import android.os.AsyncTask;import android.os.Environment;import android.util.Log;import android.widget.RemoteViews;public class AppUpdateUtils {    private static Context mContext;    private static int mVersionCode;    private static AppVersion mAppVersion;    private static String mVersionName;    private static String mFileName;    private static ProgressDialog mProgressDialog;    private static String mLocalFilepath;    private static DownloadFileAsyncTask mDownloadFileAsyncTask;    private static boolean hasCancel = false;    public static final String TAG = "AppUpDate";    // 如果是自动更新,那么就不跳出已经是最新版本的对话框。否则用户点击更新应用按钮,弹出已经是最新版本的提示框    private static boolean mIsAuto = false;    private static boolean mShowProgressDialog = false;    private static final int NOTIFY_ID = 54;    private static NotificationManager mNotificationManager;    private static Notification mNotification;    /**     * 初始化     *      * @param context     *            执行上下文     * @param newAv     *            对比版本     * @param isauto     *            指示是否是自动升级,当版本号没变时,true无响应,false弹出已是最新版的对话框。     * @param showProgressDialog     *            true弹出下载进度对话框,false为通知消息提示进度     */    public static void init(Context context, AppVersion newAv, boolean isauto,            boolean showProgressDialog) {        mIsAuto = isauto;        mShowProgressDialog = showProgressDialog;        mContext = context;        mNotificationManager = (NotificationManager) context                .getSystemService(android.content.Context.NOTIFICATION_SERVICE);        mVersionCode = getVerCode(mContext);        mVersionName = getVerName(mContext);        mAppVersion = newAv;        mFileName = mAppVersion.getApkName();        File sdDir = null;        // 判断sd卡是否存在        boolean sdCardExist = Environment.getExternalStorageState().equals(                android.os.Environment.MEDIA_MOUNTED);        if (sdCardExist) {            // 获取根目录            sdDir = Environment.getExternalStorageDirectory();        }        // 注意FileOutputStream不会自动创建路径,所以初始化的时候要主动创建路径。        String dirpath;        if (sdDir != null) {            // AppName为你想保存的路径,一般为应用目录            dirpath = sdDir.toString() + "/AppName/";        } else {            dirpath = "/AppName/";        }        File dir = new File(dirpath);        if (!dir.exists()) {            dir.mkdir();// 如果路径不存在就先创建路径        }        mLocalFilepath = dirpath + mFileName;    }    /**     * 获取版本号     *      * @param context     * @return     */    private static int getVerCode(Context context) {        int verCode = -1;        try {            verCode = context.getPackageManager().getPackageInfo(                    context.getPackageName(), 0).versionCode;        } catch (NameNotFoundException e) {            Log.e(TAG, e.getMessage());        }        return verCode;    }    /**     * 获取版本名称     *      * @param context     * @return     */    private static String getVerName(Context context) {        String verName = "";        try {            verName = context.getPackageManager().getPackageInfo(                    context.getPackageName(), 0).versionName;        } catch (NameNotFoundException e) {            Log.e(TAG, e.getMessage());        }        return verName;    }    /**     * 更新应用     */    public static void upDate() {        if (mVersionCode < mAppVersion.getVerCode()) {            doNewVersionUpdate();        } else {            notNewVersionShow();        }    }    /**     * 不执行更新     */    private static void notNewVersionShow() {        // 如果不是自动升级        if (!mIsAuto) {            StringBuffer sb = new StringBuffer();            sb.append("当前版本:");            sb.append(mVersionName);            sb.append(",\n已是最新版,无需更新。");            // 这里的提示框是我自定义的            AlertDialog ad = new AlertDialog.Builder(mContext)                    .setTitle("提示")                    .setMessage(sb.toString())                    .setPositiveButton("确认",                            new DialogInterface.OnClickListener() {                                public void onClick(DialogInterface dialog,                                        int which) {                                    // 取消                                    dialog.dismiss();                                }                            }).create();            ad.show();        }    }    /**     * 更新应用提示     */    private static void doNewVersionUpdate() {        StringBuffer sb = new StringBuffer();        sb.append("当前版本:");        sb.append(mVersionName);        sb.append(", 发现新版本:");        sb.append(mAppVersion.getVersionName()).append("\n");        sb.append("更新内容:\n");        // 这里我们使用;作为分隔符,显示多条跟新内容信息。        if (mAppVersion.getContent().contains(";")) {            String[] up = mAppVersion.getContent().split(";");            for (String s : up) {                sb.append(s).append("\n");            }        } else {            sb.append(mAppVersion.getContent()).append("\n");        }        sb.append("是否更新?");        AlertDialog ad = new AlertDialog.Builder(mContext)                .setTitle("提示")                .setMessage(sb.toString())                .setNegativeButton("取消", null)                .setPositiveButton("确认", new DialogInterface.OnClickListener() {                    @Override                    public void onClick(DialogInterface dialog, int which) {                        updateFile(mAppVersion.getUrl());                        dialog.dismiss();                    }                })                .setNegativeButton("暂不更新",                        new DialogInterface.OnClickListener() {                            public void onClick(DialogInterface dialog,                                    int whichButton) {                                // 点击"取消"按钮之后退出程序                                dialog.dismiss();                            }                        }).create();// 创建        // 显示对话框        ad.show();    }    // 执行应用更新    private static void updateFile(final String path) {        // pBar.show();        File file = new File(mLocalFilepath);        // 根据服务器传回的更新包sha1进行比对,判断是否下载完成,如果不匹配,则重新下载,否则直接打开。        if (mAppVersion.getSha1() != null) {            if (getFileSHA1(file).toUpperCase().equals(mAppVersion.getSha1())) {                openFile(file);            } else {                try {                    // downloadFile(path, localFilepath);                    mDownloadFileAsyncTask = new DownloadFileAsyncTask();                    mDownloadFileAsyncTask.execute(path);                } catch (Exception e) {                    e.printStackTrace();                }            }        } else {            try {                mDownloadFileAsyncTask = new DownloadFileAsyncTask();                mDownloadFileAsyncTask.execute(path);            } catch (Exception e) {                e.printStackTrace();            }        }    }    /**     * 取消更新     */    public void cancelUpDate() {        if (mDownloadFileAsyncTask != null) {            if (!mDownloadFileAsyncTask.isCancelled()) {                mDownloadFileAsyncTask.cancel(true);            }        }    }    /**     * 应用下载Task     *      */    private static class DownloadFileAsyncTask extends            AsyncTask<String, Integer, String> {        // 后台下载任务        @Override        protected String doInBackground(String... params) {            try {                URL url = new URL(params[0]);                URLConnection connection;                connection = url.openConnection();                // 2.2以上默认用“gzip”,这里要取消使用,否则大小永远为-1.                connection.setRequestProperty("Accept-Encoding", "identity");                connection.connect();                int length = connection.getContentLength();                InputStream input = new BufferedInputStream(                        connection.getInputStream());                FileOutputStream output = new FileOutputStream(mLocalFilepath);                byte data[] = new byte[1024];                long total = 0;                int count;                while ((count = input.read(data)) != -1) {                    if (!hasCancel) {                        total += count;                        publishProgress((int) (total * 100 / length));                        output.write(data, 0, count);                    } else {                        cancel(true);                        break;                    }                }                output.flush();                output.close();                input.close();            } catch (Exception e) {                // TODO Auto-generated catch block                e.printStackTrace();            }            return null;        }        // 进度更新        private int tempv;        @Override        protected void onProgressUpdate(Integer... values) {            // TODO Auto-generated method stub            super.onProgressUpdate(values);            // 如果需要用到进度提示框,则执行            if (mShowProgressDialog) {                if (values[0] != tempv) {                    mProgressDialog.setProgress(values[0]);                }            } else {                // 防止多次重复提示,影响性能                if (values[0] != tempv) {                    RemoteViews contentView = mNotification.contentView;                    contentView.setTextViewText(R.id.rate,                            String.valueOf(values[0]) + "%");                    contentView.setProgressBar(R.id.progress, 100, values[0],                            false);                    mNotificationManager.notify(NOTIFY_ID, mNotification);                    tempv = values[0];                }            }        }        // 下载完成后执行        @Override        protected void onPostExecute(String result) {            // TODO Auto-generated method stub            super.onPostExecute(result);            if (mShowProgressDialog) {                openFile(new File(mLocalFilepath));            } else {                Intent intent = new Intent();                intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);                intent.setAction(android.content.Intent.ACTION_VIEW);                // 设定intent的file与MimeType                intent.setDataAndType(Uri.fromFile(new File(mLocalFilepath)),                        "application/vnd.android.package-archive");                // 下载完毕后变换通知形式                mNotification.flags = Notification.FLAG_AUTO_CANCEL;                mNotification.contentView = null;                // Intent intent = new Intent(mContext, FileMgrActivity.class);                // // 告知已完成                // intent.putExtra("completed", "yes");                // //更新参数,注意flags要使用FLAG_UPDATE_CURRENT                PendingIntent contentIntent = PendingIntent.getActivity(                        mContext, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);                mNotification.setLatestEventInfo(mContext, "下载完成",                        "文件已下载完毕,点击进行安装。", contentIntent);                mNotificationManager.notify(NOTIFY_ID, mNotification);            }        }        @Override        protected void onPreExecute() {            // TODO Auto-generated method stub            super.onPreExecute();            hasCancel = false;            if (mShowProgressDialog) {                showProgressDialog();            } else {                tempv = 0;                int icon = R.drawable.ic_launcher;                CharSequence tickerText = "开始下载";                long when = System.currentTimeMillis();                mNotification = new Notification(icon, tickerText, when);                // 在通知栏上点击此通知后自动清除此通知                mNotification.flags = Notification.FLAG_AUTO_CANCEL;                RemoteViews contentView = new RemoteViews(                        mContext.getPackageName(), R.layout.notification_update);                contentView.setTextViewText(R.id.fileName, "更新文件下载中……");                // 指定个性化视图                mNotification.contentView = contentView;                Intent intent = new Intent();                PendingIntent contentIntent = PendingIntent.getActivity(                        mContext, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);                // 指定内容意图                mNotification.contentIntent = contentIntent;                mNotificationManager.notify(NOTIFY_ID, mNotification);            }        }    }    // 在手机上打开文件    private static void openFile(File f) {        // mProgressDialog.dismiss();        Intent intent = new Intent();        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);        intent.setAction(android.content.Intent.ACTION_VIEW);        // 设定intent的file与MimeType,安装文件        intent.setDataAndType(Uri.fromFile(f),                "application/vnd.android.package-archive");        mContext.startActivity(intent);    }    // 使用自带算法 获取文件的SHA1    private static String getFileSHA1(File file) {        if (file.exists()) {            MessageDigest digest = null;            byte buffer[] = new byte[1024];            int len;            try {                digest = MessageDigest.getInstance("SHA-1");// ("SHA-1");                FileInputStream in = new FileInputStream(file);                while ((len = in.read(buffer, 0, 1024)) != -1) {                    digest.update(buffer, 0, len);                }                in.close();            } catch (Exception e) {                e.printStackTrace();                return "";            }            // 直接用这玩意转换成16进制,碉堡了、            BigInteger bigInt = new BigInteger(1, digest.digest());            return bigInt.toString(16);        } else {            return "";        }    }    /**     * 显示下载进度对话框,可以取消下载任务。     */    private static void showProgressDialog() {        mProgressDialog = new ProgressDialog(mContext);        mProgressDialog.setOnCancelListener(new OnCancelListener() {            @Override            public void onCancel(DialogInterface dialog) {                if (mDownloadFileAsyncTask != null) {                    if (!mDownloadFileAsyncTask.isCancelled()) {                        mDownloadFileAsyncTask.cancel(true);                        hasCancel = true;                    }                }            }        });        mProgressDialog.setTitle("正在下载");        mProgressDialog.setMax(100);        mProgressDialog.setIndeterminate(false);        mProgressDialog.setMessage("请稍候...");        mProgressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);        mProgressDialog.show();    }}
复制代码

看起来是这样的

demo下载地址:

链接:http://pan.baidu.com/s/1eQs2vCm 密码:3gkc

 

我不怕千万人阻挡,只怕自己投降。

0 0