Android App 自动更新版本

简介: 写App以来,一直有统一的版本命名规则,之所以这样做的目的是为了App自动更新。今天看了别人怎么实现的博客,然后自己总结了一些,能力有限,不喜勿喷哦,希望大家看见有错的地方还请多多指教。kensoon918@163.com only for feedback.

概述

其实Android App自动更新这个功能是很重要的,原因就在于Android 是开源的,所以国内出现了很多Android 的应用市场,所以如果你的一个App在一个AppStore里面上线了,然后你又有一个新的版本出来了的话,如果不写自动更新的话就得一个应用市场一个应用市场的发布,是不是感觉心很累,所以自动更新版本,还是很重要的。

服务器数据

当然为了能够让你的App知道是否该更新了,所以得有一个固定的服务器,以便于你得到更新的数据。我设计的包括以下数据(可能有不足的地方,具体情况因人而异):

1.最新版本名称
2.最新版本号
3.更新内容
4.下载地址

为了方便我用的是Json来传这几个数据,像下面这样的:

{"Version_Name":"cybercar1.2.0","Version_Code":"24","Version_Update_Content":"重要更新","Version_Update_Address":"http://www.baidu.com/Apps/cybercar1.2.0.apk"}

Android代码

1. 首先得写一个判断网络链接的Util类

import android.content.Context;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
/**

  • Created by ken on 16-7-15.
  • 这个类主要是用来判断网络链接的,是否链接,是否是wi-fi链接,是否是移动网络链接
    */

public class ConnectivityUtils {

/**
 * 判断是否链接网络
 */
public static boolean isConnected(Context context) {
    try {
        ConnectivityManager connMgr =
                (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
        NetworkInfo activeInfo = connMgr.getActiveNetworkInfo();
        //返回链接状态
        if (activeInfo != null && activeInfo.isConnected()) {
            return true;
        } else {
            return false;
        }
    } catch (Exception e) {
        return false;
    }
}
//判断是否是wifi链接
public static boolean isWifiConnected(Context context) {
    try {
        ConnectivityManager connMgr =
                (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
        NetworkInfo activeInfo = connMgr.getActiveNetworkInfo();
        //返回链接状态
        if (activeInfo != null && activeInfo.isConnected()
                && activeInfo.getType() == ConnectivityManager.TYPE_WIFI) {
           return true;
        } else {
            return false;
        }
    } catch (Exception e) {
        return false;
    }
}

}



###2.然后写一个自动更新的类

>```java
import android.app.AlertDialog;
import android.app.ProgressDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.net.Uri;
import android.os.Handler;
import android.os.Message;
import com.android.volley.Response;
import com.android.volley.VolleyError;
import com.android.volley.toolbox.JsonObjectRequest;
import com.fat246.cybercar.BuildConfig;
import com.fat246.cybercar.R;
import com.fat246.cybercar.application.MyApplication;
import com.fat246.cybercar.utils.ConnectivityUtils;
import com.fat246.cybercar.utils.PreferencesUtility;
import org.json.JSONObject;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
/**
 * Created by ken on 16-7-15.
 * 自动更新App
 */
public class AutoUpdateManager implements DialogInterface.OnClickListener, Runnable {
    //服务器地址
    private static final String AUTO_UPDATE_SERVER_ADDRESS = "http://www.baidu.com/autoupdate";
    //数据key
    private static final String VERSION_NAME = "Version_Name";
    private static final String VERSION_CODE = "Version_Code";
    private static final String VERSION_UPDATE_CONTENT = "Version_Update_Content";
    private static final String VERSION_UPDATE_ADDRESS = "Version_Update_Address";
    //数据 包括 1.版本名称 2.版本号 3.版本更新内容 4.版本地址
    private String Version_Name;
    private int Version_Code;
    private String Version_Upadte_Content;
    private String Version_Update_Address;
    //上下文
    private Context context;
    //接口
    private AfterUpdate afterUpdate;
    //下载进度
    private int mProgress;
    private boolean mInteruptFlag;
    private static final int DOWN_UPDATE = 0;
    private static final int DOWN_OVER = 1;
    private Handler mHandler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
                case DOWN_UPDATE:
                    mProgressDialog.setProgress(mProgress);
                    break;
                case DOWN_OVER:
                    installApk();
                    break;
            }
        }
    };
    private ProgressDialog mProgressDialog;
    public AutoUpdateManager(Context context) {
        this.context = context;
    }
    //开始更新
    public void beginUpdate(AfterUpdate afterUpdate) {
        this.afterUpdate = afterUpdate;
        //判断是否有网络链接
        if (ConnectivityUtils.isConnected(context)) {
            //向服务器拉取数据
            pullUpdateInfo();
        } else {
            afterUpdate.toDoAfterUpdate();
        }
    }
    //拉取服务器的信息
    private void pullUpdateInfo() {
        //用Volley请求服务器最新的版本信息
        JsonObjectRequest jsonObjectRequest = new JsonObjectRequest(AUTO_UPDATE_SERVER_ADDRESS, null, new Response.Listener<JSONObject>() {
            @Override
            public void onResponse(JSONObject jsonObject) {
                paserJsonData(jsonObject);
            }
        }, new Response.ErrorListener() {
            @Override
            public void onErrorResponse(VolleyError volleyError) {
                volleyError.printStackTrace();
                afterUpdate.toDoAfterUpdate();
            }
        });
        //设置Tag
        jsonObjectRequest.setTag(AUTO_UPDATE_SERVER_ADDRESS);
        //添加到请求队列里面
        MyApplication.getRequestQueue().add(jsonObjectRequest);
    }
    //解析 Json数据
    private void paserJsonData(JSONObject json) {
        try {
            //版本名称
            Version_Name = json.getString(VERSION_NAME);
            //版本号
            Version_Code = json.getInt(VERSION_CODE);
            //版本更新内容
            Version_Upadte_Content = json.getString(VERSION_UPDATE_CONTENT);
            //版本地址
            Version_Update_Address = json.getString(VERSION_UPDATE_ADDRESS);
            //判断是否要提醒用户更新
            if (isNeedUpdate()) {
                //显示提示Dialog
                showUpdateDialog();
            } else {
                afterUpdate.toDoAfterUpdate();
            }
        } catch (Exception e) {
            e.printStackTrace();
            afterUpdate.toDoAfterUpdate();
        }
    }
    //判断是否需要更新
    private boolean isNeedUpdate() {
        try {
            //判断服务器最新的版本号是否大于当前版本号
            if (Version_Code > BuildConfig.VERSION_CODE) {
                //首先得到跳过的版本号
                int jump_code = PreferencesUtility.getInstance(context).getJumpVersionCode();
                //判断跳过的版本号是否大于当前服务器版本号
                if (Version_Code > jump_code) {
                    return true;
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
        return false;
    }
    //显示更新提示
    private void showUpdateDialog() {
        try {
            //builder
            AlertDialog.Builder builder = new AlertDialog.Builder(context);
            //设置标题
            builder.setTitle("版本更新");
            //更新内容
            builder.setMessage(Version_Upadte_Content);
            //设置图标
            builder.setIcon(R.mipmap.ic_launcher);
            //设置以后更新
            builder.setPositiveButton("以后更新", this);
            //设置立即更新
            builder.setNegativeButton("立即更新", this);
            //设置跳过当前版本
            builder.setNeutralButton("跳过版本", this);
            //创建Dialog 并展示
            AlertDialog dialog = builder.create();
            //设置点击外面不消失
            dialog.setCanceledOnTouchOutside(false);
            dialog.show();
        } catch (Exception e) {
            e.printStackTrace();
            afterUpdate.toDoAfterUpdate();
        }
    }
    //当更新完成后要做的事情
    public interface AfterUpdate {
        void toDoAfterUpdate();
    }
    //Dialog的点击事件
    @Override
    public void onClick(DialogInterface dialog, int which) {
        switch (which) {
            case AlertDialog.BUTTON_POSITIVE:
                afterUpdate.toDoAfterUpdate();
                break;
            case AlertDialog.BUTTON_NEGATIVE:
                toUpdateUtils();
                break;
            case AlertDialog.BUTTON_NEUTRAL:
                //设置跳过版本               PreferencesUtility.getInstance(context).setJumpVersionCode(Version_Code);
                afterUpdate.toDoAfterUpdate();
                break;
        }
    }
    //点击立即更新按钮
    public void toUpdateUtils() {
        //判断是否是wifi链接
        if (ConnectivityUtils.isWifiConnected(context)) {
            toDownlaodApk();
        } else {
            //友情提示用户
            showOurFriendly();
        }
    }
    //友情提示用户
    private void showOurFriendly() {
        AlertDialog.Builder builder = new AlertDialog.Builder(context);
        builder.setTitle("友情提示");
        builder.setMessage("亲,你用的不是Wifi,是否继续下载?");
        builder.setPositiveButton("是", new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int which) {
                toDownlaodApk();
                afterUpdate.toDoAfterUpdate();
            }
        });
        builder.setNegativeButton("取消", new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int which) {
                afterUpdate.toDoAfterUpdate();
            }
        });
        AlertDialog alertDialog = builder.create();
        alertDialog.setCanceledOnTouchOutside(false);
        alertDialog.show();
    }
    //去下载
    private void toDownlaodApk() {
        Thread update = new Thread(this);
        showDownlaodProgressBar();
        update.start();
    }
    //显示下载ProgressBar
    private void showDownlaodProgressBar() {
        mProgressDialog = new ProgressDialog(context);
        mProgressDialog.setMessage("正在下载...");
        mProgressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
        mProgressDialog.setButton("取消下载", new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int which) {
                mProgressDialog.dismiss();
                mInteruptFlag = true;
                afterUpdate.toDoAfterUpdate();
            }
        });
        mProgressDialog.setCanceledOnTouchOutside(false);
        mProgressDialog.setProgress(0);
        mProgressDialog.setMax(100);
        mProgressDialog.show();
    }
    @Override
    public void run() {
        //判空
        if (Version_Update_Address == null) {
            return;
        }
        FileOutputStream fos = null;
        InputStream is = null;
        try {
            URL url = new URL(Version_Update_Address);
            HttpURLConnection conn = (HttpURLConnection) url.openConnection();
            conn.connect();
            int length = conn.getContentLength();
            is = conn.getInputStream();
            //保存到的文件夹
            File file = new File(MyApplication.SAVE_PATH + "/Apk/");
            if (!file.exists()) {
                file.mkdir();
            }
            File apkFile = new File(MyApplication.SAVE_PATH + "/Apk/" + Version_Name + ".apk");
            fos = new FileOutputStream(apkFile);
            int count = 0;
            byte buf[] = new byte[1024];
            do {
                int len = is.read(buf);
                if (len != -1) {
                    count += len;
                    mProgress = (int) (((float) count / length) * 100);
                    mHandler.sendEmptyMessage(DOWN_UPDATE);
                } else {
                    mHandler.sendEmptyMessage(DOWN_OVER);
                    break;
                }
                fos.write(buf, 0, len);
            } while (!mInteruptFlag);
        } catch (MalformedURLException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            mProgressDialog.dismiss();
            if (null != is) {
                try {
                    is.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (null != fos) {
                try {
                    fos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
    //安装下载好的版本
    private void installApk() {
        File apkFile = new File(MyApplication.SAVE_PATH + "/Apk/" + Version_Name + ".apk");
        if (!apkFile.exists()) {
            return;
        }
        //开启安装界面
        Intent i = new Intent(Intent.ACTION_VIEW);
        i.setDataAndType(Uri.parse("file://" + apkFile.toString()), "application/vnd.android.package-archive");
        context.startActivity(i);
        //如果不杀进程不会跳到安装后打开的页面
        android.os.Process.killProcess(android.os.Process.myPid());
    }
}
目录
相关文章
|
1月前
|
XML Java 数据库
安卓项目:app注册/登录界面设计
本文介绍了如何设计一个Android应用的注册/登录界面,包括布局文件的创建、登录和注册逻辑的实现,以及运行效果的展示。
129 0
安卓项目:app注册/登录界面设计
|
2月前
|
Java 数据库 Android开发
一个Android App最少有几个线程?实现多线程的方式有哪些?
本文介绍了Android多线程编程的重要性及其实现方法,涵盖了基本概念、常见线程类型(如主线程、工作线程)以及多种多线程实现方式(如`Thread`、`HandlerThread`、`Executors`、Kotlin协程等)。通过合理的多线程管理,可大幅提升应用性能和用户体验。
113 15
一个Android App最少有几个线程?实现多线程的方式有哪些?
|
28天前
|
存储 API 数据库
uniapp APP自动更新组件
uniapp APP自动更新组件
59 1
|
2月前
|
存储 开发工具 Android开发
使用.NET MAUI开发第一个安卓APP
【9月更文挑战第24天】使用.NET MAUI开发首个安卓APP需完成以下步骤:首先,安装Visual Studio 2022并勾选“.NET Multi-platform App UI development”工作负载;接着,安装Android SDK。然后,创建新项目时选择“.NET Multi-platform App (MAUI)”模板,并仅针对Android平台进行配置。了解项目结构,包括`.csproj`配置文件、`Properties`配置文件夹、平台特定代码及共享代码等。
128 2
|
2月前
|
XML Android开发 数据格式
🌐Android国际化与本地化全攻略!让你的App走遍全球无障碍!🌍
在全球化背景下,实现Android应用的国际化与本地化至关重要。本文以一款旅游指南App为例,详细介绍如何通过资源文件拆分与命名、适配布局与方向、处理日期时间及货币格式、考虑文化习俗等步骤,完成多语言支持和本地化调整。通过邀请用户测试并收集反馈,确保应用能无缝融入不同市场,提升用户体验与满意度。
88 3
|
1月前
|
开发工具 iOS开发 MacOS
【Mac_mistake】app不能安装在未命名需要OSv11.13或更高版本
【Mac_mistake】app不能安装在未命名需要OSv11.13或更高版本
59 0
|
1月前
|
安全 网络安全 Android开发
深度解析:利用Universal Links与Android App Links实现无缝网页至应用跳转的安全考量
【10月更文挑战第2天】在移动互联网时代,用户经常需要从网页无缝跳转到移动应用中。这种跳转不仅需要提供流畅的用户体验,还要确保安全性。本文将深入探讨如何利用Universal Links(仅限于iOS)和Android App Links技术实现这一目标,并分析其安全性。
183 0
|
2月前
|
Java 数据库 Android开发
一个Android App最少有几个线程?实现多线程的方式有哪些?
本文介绍了Android应用开发中的多线程编程,涵盖基本概念、常见实现方式及最佳实践。主要内容包括主线程与工作线程的作用、多线程的多种实现方法(如 `Thread`、`HandlerThread`、`Executors` 和 Kotlin 协程),以及如何避免内存泄漏和合理使用线程池。通过有效的多线程管理,可以显著提升应用性能和用户体验。
69 10
|
2月前
|
XML 数据库 Android开发
10分钟手把手教你用Android手撸一个简易的个人记账App
该文章提供了使用Android Studio从零开始创建一个简单的个人记账应用的详细步骤,包括项目搭建、界面设计、数据库处理及各功能模块的实现方法。
|
3月前
|
API Android开发
Android P 性能优化:创建APP进程白名单,杀死白名单之外的进程
本文介绍了在Android P系统中通过创建应用进程白名单并杀死白名单之外的进程来优化性能的方法,包括设置权限、获取运行中的APP列表、配置白名单以及在应用启动时杀死非白名单进程的代码实现。
61 1
下一篇
无影云桌面