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());
    }
}
目录
相关文章
|
7月前
|
Android开发 数据安全/隐私保护 开发者
Android自定义view之模仿登录界面文本输入框(华为云APP)
本文介绍了一款自定义输入框的实现,包含静态效果、hint值浮动动画及功能扩展。通过组合多个控件完成界面布局,使用TranslateAnimation与AlphaAnimation实现hint文字上下浮动效果,支持密码加密解密显示、去除键盘回车空格输入、光标定位等功能。代码基于Android平台,提供完整源码与attrs配置,方便复用与定制。希望对开发者有所帮助。
128 0
|
10月前
|
JavaScript 前端开发 Android开发
【03】仿站技术之python技术,看完学会再也不用去购买收费工具了-修改整体页面做好安卓下载发给客户-并且开始提交网站公安备案-作为APP下载落地页文娱产品一定要备案-包括安卓android下载(简单)-ios苹果plist下载(稍微麻烦一丢丢)-优雅草卓伊凡
【03】仿站技术之python技术,看完学会再也不用去购买收费工具了-修改整体页面做好安卓下载发给客户-并且开始提交网站公安备案-作为APP下载落地页文娱产品一定要备案-包括安卓android下载(简单)-ios苹果plist下载(稍微麻烦一丢丢)-优雅草卓伊凡
346 13
【03】仿站技术之python技术,看完学会再也不用去购买收费工具了-修改整体页面做好安卓下载发给客户-并且开始提交网站公安备案-作为APP下载落地页文娱产品一定要备案-包括安卓android下载(简单)-ios苹果plist下载(稍微麻烦一丢丢)-优雅草卓伊凡
|
5月前
|
存储 机器学习/深度学习 API
Android API Level 到底是什么?和安卓什么关系?应用发布如何知道自己的版本?优雅草卓伊凡
Android API Level 到底是什么?和安卓什么关系?应用发布如何知道自己的版本?优雅草卓伊凡
801 31
Android API Level 到底是什么?和安卓什么关系?应用发布如何知道自己的版本?优雅草卓伊凡
|
5月前
|
存储 Android开发 数据安全/隐私保护
Thanox安卓系统增加工具下载,管理、阻止、限制后台每个APP运行情况
Thanox是一款Android系统管理工具,专注于权限、后台启动及运行管理。支持应用冻结、系统优化、UI自定义和模块管理,基于Xposed框架开发,安全可靠且开源免费,兼容Android 6.0及以上版本。
434 4
|
5月前
|
iOS开发 MacOS
如何指定下载不同版本macOS app
本文介绍了多种下载和安装 macOS 的方法,包括使用终端命令下载指定版本的 macOS App 或 PKG 文件,以及通过脚本工具如 installinstallmacos.py 和 fetch-installer-pkg 实现自动化下载。同时还讲解了如何将 macOS 安装程序制作成可启动 U 盘,适用于系统重装或部署场景。
|
8月前
|
数据采集 JSON 网络安全
移动端数据抓取:Android App的TLS流量解密方案
本文介绍了一种通过TLS流量解密技术抓取知乎App热榜数据的方法。利用Charles Proxy解密HTTPS流量,分析App与服务器通信内容;结合Python Requests库模拟请求,配置特定请求头以绕过反爬机制。同时使用代理IP隐藏真实IP地址,确保抓取稳定。最终成功提取热榜标题、内容简介、链接等信息,为分析热点话题和用户趋势提供数据支持。此方法也可应用于其他Android App的数据采集,但需注意选择可靠的代理服务。
326 11
移动端数据抓取:Android App的TLS流量解密方案
|
7月前
【Function App】在PowerShell Function中指定特殊的Microsoft.Graph.Users版本
在Azure Function App中运行PowerShell Function时,通过Requirements.psd1文件管理模块版本。若需将“Microsoft.Graph.Users”从最新版2.26.0改回2.23.0以避免冲突,可通过以下步骤解决:1) 在requirements.psd1中明确指定版本为2.23.0 2) 在profile.ps1中添加`Import-Module Microsoft.Graph.Users -RequiredVersion 2.23.0`语句。此方法确保加载特定版本模块
145 18
|
10月前
|
移动开发 安全 Java
Android历史版本与APK文件结构
通过以上内容,您可以全面了解Android的历史版本及其主要特性,同时掌握APK文件的结构和各部分的作用。这些知识对于理解Android应用的开发和发布过程非常重要,也有助于在实际开发中进行高效的应用管理和优化。希望这些内容对您的学习和工作有所帮助。
967 83
|
8月前
|
Java API 开发工具
Android cmdline-tools版本与最小JDK的关系
总的来说,Android的命令行工具和JDK之间的关系就像是一场舞会,两者需要彼此配合,才能共同创造出美妙的舞蹈。如果选择了不合适的舞伴(即不兼容的版本),可能会导致舞蹈中的步伐混乱,甚至无法完成舞蹈。而即使选择了合适的舞伴,也需要考虑舞伴的舞蹈技巧(即性能和稳定性),才能确保舞蹈的完美表现。因此,选择合适的Android命令行工具和JDK版本,是每一个Android开发者都需要面对的重要决定。
250 13
|
9月前
|
安全 开发工具 Android开发
【Android Git】Git版本回退方式
在实际操作中,选择合适的版本回退方式,可以有效地管理代码版本,提高开发效率和代码质量。
497 26

热门文章

最新文章