Android应用的升级更新功能

Android应用的版本升级

这是一个Android应用的自动更新功能,其中的版本控制使用的是XML文档,在服务器放一个版本控制文档version.xml从服务器获取版本内容,与本地的版本进行对比,更新使用的是Android系统提供的DownloadManager使用比较简单

首先是服务器的version.xml的格式

<?xml version="1.0" encoding="utf-8" ?>
<info>
  <appName></appName>
  <versionCode></versionCode>
  <versionName></versionName>
  <downUrl></downUrl>
  <description></description>
</info>

其中的appName、versionCode、versionName不用多说,description中放的内容是新版本的提示信息如果有多条的话可以用英文的“;”做分隔符。

然后是读取服务器的版本信息

public class ReadServerVersion {

    private String url;
    private UpdateInfo updateInfo;
    private static ReadServerVersion instance;

    private ReadServerVersion(String url) {
        this.url = url;
        readVersionInfo();
    }

    public static ReadServerVersion getInstance(String url) {
        if (instance == null) {
            instance = new ReadServerVersion(url);
        }
        return instance;
    }

    /**
     * @描述:读取服务器的版本内容
     */
    public void readVersionInfo() {
        new Thread(new Runnable() {

            @Override
            public void run() {
                // TODO Auto-generated method stub
                HttpURLConnection urlConn;
                try {
                    urlConn = (HttpURLConnection) new URL(url).openConnection();
                    urlConn.setDoInput(true);
                    urlConn.setUseCaches(false);
                    urlConn.setConnectTimeout(3000);// 设置连接超时
                    InputStream in = urlConn.getInputStream();
                    updateInfo = ParseXml.parseXml(in);
                    urlConn.disconnect();
                    in.close();
                } catch (Exception e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
        }).start();
    }

    /**
     * @描述:获取服务器的版本号
     * @return
     */
    public int getVersionCode() {
        return updateInfo == null ? null : updateInfo.getVersionCode();
    }

    /**
     * @描述:获取服务器的版本名
     * @return
     */
    public String getVersionName() {
        return updateInfo == null ? null : updateInfo.getVersionName();
    }

    /**
     * @描述:获取更新提示信息
     * @return
     */
    public StringBuilder getTipsInfo() {
        return updateInfo == null ? null : updateInfo.getDescription();
    }

    /**
     * @描述:获取下载地址
     * @return
     */
    public String getDownUrl() {
        return updateInfo == null ? null : updateInfo.getDownUrl();
    }

    /**
     * @描述:判断服务器是否有新版本
     * @param context
     * @return
     */
    public boolean hasNewVersion(Context context) {
        boolean hasNewVersion = false;
        if (updateInfo == null) {
            return hasNewVersion;
        }
        return updateInfo.getVersionCode() > getVersionCode(context) ? true
                : false;
    }

    /**
     * @描述:获取应用的版本信号
     * @param context
     * @return
     */
    private int getVersionCode(Context context) {
        int versionCode = 0;
        try {
            versionCode = context.getPackageManager().getPackageInfo(
                    context.getPackageName(), 0).versionCode;
        } catch (NameNotFoundException e) {
            e.printStackTrace();
        }
        return versionCode;
    }
}

UpdateInfo.java

public class UpdateInfo {

    /** 应用名称 **/
    private String appName;
    /** 版本号 **/
    private int versionCode;
    /** 版本名 **/
    private String versionName;
    /** 更新地址 **/
    private String downUrl;
    /** 更新描述 **/
    private String description;

    /**
     * @param versionCode
     * @param versionName
     * @param downUrl
     * @param description
     */
    public UpdateInfo(String appName, int versionCode, String versionName,
            String downUrl, String description) {
        super();
        this.appName = appName;
        this.versionCode = versionCode;
        this.versionName = versionName;
        this.downUrl = downUrl;
        this.description = description;
    }

    /**  
     *   
     */
    public UpdateInfo() {
        super();
    }

    public int getVersionCode() {
        return versionCode;
    }

    public void setVersionCode(int versionCode) {
        this.versionCode = versionCode;
    }

    public String getVersionName() {
        return versionName;
    }

    public void setVersionName(String versionName) {
        this.versionName = versionName;
    }

    public String getDownUrl() {
        return downUrl;
    }

    public void setDownUrl(String downUrl) {
        this.downUrl = downUrl;
    }

    public StringBuilder getDescription() {
        String[] tips = description.split(";");
        StringBuilder updateContent = new StringBuilder();
        for (int i = 0; i < tips.length; i++) {
            if (i != tips.length - 1) {
                updateContent.append(tips[i] + "\n");
            } else {
                updateContent.append(tips[i]);
            }
        }

        return updateContent;
    }

    public void setDescription(String description) {
        this.description = description;
    }

    public String getAppName() {
        return appName;
    }

    public void setAppName(String appName) {
        this.appName = appName;
    }

}

解析服从服务器读取的版本信息

public class ParseXml {

    /**
     * @描述:解析从服务器上读取到的版本文档,由于XML文件比较小,因此使用DOM方式进行解析
     * @param in
     * @return
     * @throws Exception
     */
    public static UpdateInfo parseXml(InputStream in) throws Exception {
        UpdateInfo updateInfo = null;
        // 实例化一个文档构建器工厂
        DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
        // 通过文档构建器工厂获取一个文档构建器
        DocumentBuilder builder = factory.newDocumentBuilder();
        // 通过文档通过文档构建器构建一个文档实例
        Document document = builder.parse(in);
        // 获取XML文件根节点
        Element root = document.getDocumentElement();
        // 获得所有子节点
        NodeList childNodes = root.getChildNodes();

        String appName = null;
        int versionCode = -1;
        String versionName = null;
        String downUrl = null;
        String description = null;

        for (int j = 0; j < childNodes.getLength(); j++) {
            Node childNode = childNodes.item(j);
            if (childNode.getNodeType() == Node.ELEMENT_NODE) {
                Element childElement = (Element) childNode;
                if ("appName".equals(childElement.getNodeName())) {
                    appName = childElement.getFirstChild().getNodeValue();
                } else if ("versionCode".equals(childElement.getNodeName())) {
                    versionCode = Integer.parseInt(childElement.getFirstChild()
                            .getNodeValue());
                } else if (("versionName".equals(childElement.getNodeName()))) {
                    versionName = childNode.getFirstChild().getNodeValue();
                } else if (("downUrl".equals(childElement.getNodeName()))) {
                    downUrl = childElement.getFirstChild().getNodeValue();
                } else if ("description".equals(childElement.getNodeName())) {
                    description = childElement.getFirstChild().getNodeValue();
                }
            }
        }
        updateInfo = new UpdateInfo(appName, versionCode, versionName, downUrl,
                description);
        return updateInfo;
    }

}

UpdateUtils.java

public class UpdateUtils {

    public static String PREFERENCE_NAME = "VersionUpdate";

    /**
     * put long preferences
     * 
     * @param context
     * @param key The name of the preference to modify
     * @param value The new value for the preference
     * @return True if the new values were successfully written to persistent storage.
     */
    public static boolean putLong(Context context, String key, long value) {
        SharedPreferences settings = context.getSharedPreferences(PREFERENCE_NAME, Context.MODE_PRIVATE);
        SharedPreferences.Editor editor = settings.edit();
        editor.putLong(key, value);
        return editor.commit();
    }

    /**
     * get long preferences
     * 
     * @param context
     * @param key The name of the preference to retrieve
     * @return The preference value if it exists, or -1. Throws ClassCastException if there is a preference with this
     *         name that is not a long
     * @see #getLong(Context, String, long)
     */
    public static long getLong(Context context, String key) {
        return getLong(context, key, -1);
    }

    /**
     * get long preferences
     * 
     * @param context
     * @param key The name of the preference to retrieve
     * @param defaultValue Value to return if this preference does not exist
     * @return The preference value if it exists, or defValue. Throws ClassCastException if there is a preference with
     *         this name that is not a long
     */
    public static long getLong(Context context, String key, long defaultValue) {
        SharedPreferences settings = context.getSharedPreferences(PREFERENCE_NAME, Context.MODE_PRIVATE);
        return settings.getLong(key, defaultValue);
    }

    /**
     * remove obj in preferences 
     * @param context
     * @param key
     * @return
     */
    public static boolean removeSharedPreferenceByKey(Context context, String key){
        SharedPreferences settings = context.getSharedPreferences(PREFERENCE_NAME, Context.MODE_PRIVATE);
        SharedPreferences.Editor editor = settings.edit();
        editor.remove(key);
        return editor.commit();
    }
}

更新的管理类

public class UpdateManager {

    private static final String VERSIONURL = "这里是服务器的version.xml的路径";
    private static UpdateManager manager;
    private ReadServerVersion serverVersion;

    private UpdateManager(){

    }

    public static UpdateManager getInstance(){
        if(manager == null){
            manager = new UpdateManager();
        }
        return manager;
    }

    public void init(){
        serverVersion = ReadServerVersion.getInstance(VERSIONURL);
    }

    public void Update(Context context){
        if(serverVersion.hasNewVersion(context)){
            showDialog(context);
        }
    }

    private void showDialog(final Context context){
        Dialog dialog = new AlertDialog.Builder(context)
//      .setIcon(R.drawable.ic_launcher)
        .setTitle("更新提示")
        .setMessage(serverVersion.getTipsInfo())
        .setPositiveButton("后台更新", new DialogInterface.OnClickListener() {

            @Override
            public void onClick(DialogInterface arg0, int arg1) {
                // TODO Auto-generated method stub
                //下载应用
                new ApkDownLoad(context, serverVersion.getDownUrl(), "应用名", "版本升级").execute();
            }
        })
        .setNegativeButton("取消", new DialogInterface.OnClickListener() {

            @Override
            public void onClick(DialogInterface arg0, int arg1) {
                // TODO Auto-generated method stub
                arg0.cancel();
            }
        })
        .create();
        dialog.show();
    }

}

使用系统的DownloadManager下载apk文件

public class ApkDownLoad {

    public static final String DOWNLOAD_FOLDER_NAME = "Download";
    public static final String DOWNLOAD_FILE_NAME   = "存放的文件名.apk";
    public static final String APK_DOWNLOAD_ID = "apkDownloadId";

    private Context context;
    private String url;
    private String notificationTitle;
    private String notificationDescription;

    private DownloadManager downloadManager;
    private CompleteReceiver completeReceiver;

    /**
     * @param context 
     * @param url 下载apk的url
     * @param notificationTitle 通知栏标题
     * @param notificationDescription 通知栏描述
     */
    public ApkDownLoad(Context context, String url, String notificationTitle,
            String notificationDescription) {
        super();
        this.context = context;
        this.url = url;
        this.notificationTitle = notificationTitle;
        this.notificationDescription = notificationDescription;

        downloadManager = (DownloadManager)context.getSystemService(Context.DOWNLOAD_SERVICE);
        completeReceiver = new CompleteReceiver();

        /** register download success broadcast **/
        context.registerReceiver(completeReceiver, new IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE));
    }

    public void execute() {

        //清除已下载的内容重新下载
        long downloadId = UpdateUtils.getLong(context, APK_DOWNLOAD_ID);
        if(downloadId != -1){
            downloadManager.remove(downloadId); 
            UpdateUtils.removeSharedPreferenceByKey(context, APK_DOWNLOAD_ID);
        }

        Request request = new Request(Uri.parse(url));
        //设置Notification中显示的文字
        request.setTitle(notificationTitle);
        request.setDescription(notificationDescription);
        //设置可用的网络类型
        request.setAllowedNetworkTypes(Request.NETWORK_MOBILE  | Request.NETWORK_WIFI); 
        //设置状态栏中显示Notification
        request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED);
        //不显示下载界面  
        request.setVisibleInDownloadsUi(false); 
        //设置下载后文件存放的位置
        File folder = Environment.getExternalStoragePublicDirectory(DOWNLOAD_FOLDER_NAME);
        if (!folder.exists() || !folder.isDirectory()) {
            folder.mkdirs();
        }
        //设置下载文件的保存路径
        request.setDestinationInExternalPublicDir(DOWNLOAD_FOLDER_NAME, DOWNLOAD_FILE_NAME);
        //设置文件类型  
        MimeTypeMap mimeTypeMap = MimeTypeMap.getSingleton();  
        String mimeString = mimeTypeMap.getMimeTypeFromExtension(MimeTypeMap.getFileExtensionFromUrl(url));  
        request.setMimeType(mimeString); 
        //保存返回唯一的downloadId
        UpdateUtils.putLong(context, APK_DOWNLOAD_ID, downloadManager.enqueue(request));
    }

    class CompleteReceiver extends BroadcastReceiver {

        @Override
        public void onReceive(Context context, Intent intent) {
            /**
             * get the id of download which have download success, if the id is my id and it's status is successful,
             * then install it
             **/
            long completeDownloadId = intent.getLongExtra(DownloadManager.EXTRA_DOWNLOAD_ID, 0);
            long downloadId = UpdateUtils.getLong(context, APK_DOWNLOAD_ID);

            if (completeDownloadId == downloadId) {

                // if download successful
                if (queryDownloadStatus(downloadManager, downloadId) == DownloadManager.STATUS_SUCCESSFUL) {

                    //clear downloadId
                    UpdateUtils.removeSharedPreferenceByKey(context, APK_DOWNLOAD_ID);

                    //unregisterReceiver
                    context.unregisterReceiver(completeReceiver);

                    //install apk
                    String apkFilePath = new StringBuilder(Environment.getExternalStorageDirectory().getAbsolutePath())
                            .append(File.separator).append(DOWNLOAD_FOLDER_NAME).append(File.separator)
                            .append(DOWNLOAD_FILE_NAME).toString();
                    install(context, apkFilePath);
                }
            }
        }
    };

    /** 查询下载状态 */
    public static int queryDownloadStatus(DownloadManager downloadManager, long downloadId){
         int result = -1;
         DownloadManager.Query query = new DownloadManager.Query().setFilterById(downloadId);
         Cursor c = null;
         try {
             c = downloadManager.query(query);
             if (c != null && c.moveToFirst()) {
                 result = c.getInt(c.getColumnIndex(DownloadManager.COLUMN_STATUS));
             }
         } finally {
             if (c != null) {
                 c.close();
             }
         }
         return result;
    }

    /**
     * install app
     * 
     * @param context
     * @param filePath
     * @return whether apk exist
     */
    public static boolean install(Context context, String filePath) {
        Intent i = new Intent(Intent.ACTION_VIEW);
        File file = new File(filePath);
        if (file != null && file.length() > 0 && file.exists() && file.isFile()) {
            i.setDataAndType(Uri.parse("file://" + filePath), "application/vnd.android.package-archive");
            i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
            context.startActivity(i);
            return true;
        }
        return false;
    }

}

在使用的过程中首先需要在application中调用UpdateManger的init方法,然后在需要进行检测的地方调用UpdateManger的update方法即可。

猜你喜欢

转载自blog.csdn.net/coward_/article/details/44811975