Android——app的版本更新(强制更新/非强制更新)

1.App版本检测:

要实现App的更新下载,我们上面介绍了,前提是服务器要保存一个App的版本号(通常的方式是保存versionCode,当然你要对比versionName也没关系)。当用户去手动检测版本,或者进入首页自动检测时,第一步是需要请求服务器的版本号,拿到版本号之后与当前App版本号(当前版本号可通过PackageInfo获取)进行对比。服务器返回的版本号大于当前App版本号,证明App已经有更新,那么进入第2步。

2.Apk下载

Apk文件是保存在服务器的。我们可以通过Http流将其下载到本地手机,然后更新安装。Android中下载的方式很多种:HttpUrlConnection,Retrofit,okHttp,以及android原生的下载工具类DownLoadManager 等等。我们采用的方式是Google推荐的下载工具类DownLoadManager。关于DownLoadManager的使用其实很简单,简单概括如下:

(1)通过getSystemService获取DownLoadManager。

(2)初始化DownLoadManager的Request,构建下载请求。

(3)调用DownLoadManager的enqueue异步发起请求,该方法返回值为标识当前下载任务的id,即downloadId。

(4)当下载完成后,系统会发出条件为android.intent.action.DOWNLOAD_COMPLETE的广播,我们可以自定义广播接受器,然后在onReceive中处理下载完成的逻辑即可。

我们使用OkHttp实现版本更新下载:

添加依赖:

compile 'com.google.code.gson:gson:2.8.2'
compile 'com.squareup.okhttp3:okhttp:3.9.1'

封装OKHttpUtils

public class OKHttpUtils {
    private static volatile OKHttpUtils instance;
    private final OkHttpClient client;

    private Handler handler = new Handler();
    private OKHttpUtils(){
        client = new OkHttpClient();
    }
    public static OKHttpUtils getInstance(){
        if (null == instance){
            synchronized (OKHttpUtils.class){
                if (instance==null){
                    instance = new OKHttpUtils();
                }
            }
        }
        return instance;
    }
    public void get(String url, Map<String, String> map, final NetCallBack callBack, final Class clazz) {
        // http://www.wuxirui.com/api/checkversion.php?version=2.0.2&from=android
        // 1.http://www.wuxirui.com/api/checkversion.php
        // 2.http://www.wuxirui.com/api/checkversion.php?version=2.0.2 &
        // 3.http://www.wuxirui.com/api/checkversion.php?

        if (TextUtils.isEmpty(url)) {
            return;
        }

        StringBuffer sb = new StringBuffer(url);

        // 是否含有? 23        if (url.contains("?")) {
            // 问号是否是最后一个字符,是3 2
            if (url.endsWith("?")) {
                for (Map.Entry entry : map.entrySet()) {
                    sb.append(entry.getKey())
                            .append("=")
                            .append(entry.getValue())
                            .append("&");
                }
            } else { // 问号不是最后一个字符2
                for (Map.Entry entry : map.entrySet()) {
                    sb.append("&")
                            .append(entry.getKey())
                            .append("=")
                            .append(entry.getValue());
                }
                sb.append("&");
            }
        } else { // 不包含?
            if (!map.isEmpty()) {
                sb.append("?");
                for (Map.Entry entry : map.entrySet()) {
                    sb.append(entry.getKey())
                            .append("=")
                            .append(entry.getValue())
                            .append("&");
                }
            }
        }

        sb.deleteCharAt(sb.lastIndexOf("&"));
        Log.i("zzz", "get url is: " + sb);

        Request request = new Request.Builder()
                .url(sb.toString())
                .get()
                .build();

        Call call = client.newCall(request);
        call.enqueue(new Callback() {
            @Override
            public void onFailure(Call call, final IOException e) {
                Log.e("zzz", "onFailure: " + e.getMessage());
                handler.post(new Runnable() {
                    @Override
                    public void run() {
                        callBack.onFailed(e);
                    }
                });

            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {
                String result = response.body().string();
                Log.i("zzz", "onResponse: " + result);
                if (!TextUtils.isEmpty(result)) {
                    Gson gson = GsonUtils.getInstance();

                    final Object o = gson.fromJson(result, clazz);
                    handler.post(new Runnable() {
                        @Override
                        public void run() {
                            callBack.onSuccess(o);
                        }
                    });
                }
            }
        });
    }
    public void download(String url, final File file, final DownLoadListener listener) {
//        /sdcard/download/aaa.apk
        // 父目录是否存在
        File parent = file.getParentFile();
        if (!parent.exists()) {
            parent.mkdir();
        }
        // 文件是否存在
        if (!file.exists()) {
            try {
                file.createNewFile();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        Request request = new Request.Builder()
                .url(url)
                .build();

        Call call = client.newCall(request);

        call.enqueue(new Callback() {
            @Override
            public void onFailure(Call call, final IOException e) {
                handler.post(new Runnable() {
                    @Override
                    public void run() {
                        listener.failed(e);
                    }
                });
            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {
                ResponseBody body = response.body();
                // 获取文件总长度
                long totalLength = body.contentLength();
                try {
                    InputStream is = body.byteStream();
                    FileOutputStream fos = new FileOutputStream(file);
                    byte[] buf = new byte[2048];
                    int length = 0;
                    int sum = 0;
                    while ((length = is.read(buf, 0, buf.length)) != -1) {
                        sum += length;
                        long progress = sum * 100 / totalLength;
                        listener.progress(progress);
                        fos.write(buf, 0, length);
                    }
                    fos.flush();
                    is.close();
                    fos.close();
                    listener.success(file.getAbsolutePath());
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        });

    }
}
定义接口:

NetCallBack

public interface NetCallBack {
    void onSuccess(Object o);
    void onFailed(Exception e);
}
DownLoadListener

public interface DownLoadListener {
    void success(String path);
    void failed(Exception e);
    void progress(long progress);
}
gson单例模式:

GsonUtils

public class GsonUtils {
    private static Gson instance;
        private GsonUtils(){

        }
        public static Gson getInstance(){
            if (instance==null){
                instance = new Gson();
            }
            return instance;
        }
}
VersionUtils

public class VersionUtils {
    public static String getVersionName(Context context) {
        String versionName = "";
        PackageManager packageManager = context.getPackageManager();

        String packageName = context.getPackageName();

        try {
            PackageInfo packageInfo = packageManager.getPackageInfo(packageName, 0);
            versionName = packageInfo.versionName;

        } catch (PackageManager.NameNotFoundException e) {
            e.printStackTrace();
        }

        return versionName;

    }
}
MainActivity

public class MainActivity extends AppCompatActivity {
    private static final String TAG = "MainActivity";
    private String updateUrl = "http://www.wuxirui.com/api/checkversion.php";

    //http://www.wuxirui.com/download/jinritoutiao.apk

    private String path = "/download/";
    private Button btn;
    private ProgressBar progressBar;
    private TextView tv_pro;

    @SuppressLint("HandlerLeak")
    private Handler handler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            int i = msg.what;
            if (i==100){
                tv_pro.setVisibility(View.GONE);
                progressBar.setVisibility(View.GONE);
            }else {
                tv_pro.setText(i + "%");
                progressBar.setProgress(i);

            }

        }
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        btn = findViewById(R.id.btn);
        progressBar = findViewById(R.id.progressBar);
        tv_pro = findViewById(R.id.tv_pro);

        String versionName = VersionUtils.getVersionName(this);
        Log.i("zzz", "versionName: " + versionName);

        Map<String, String> map = new HashMap<>();
        map.put("version", versionName);

        //
        if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
            File externalStorageDirectory = Environment.getExternalStorageDirectory();
            // /sdcard/download/
            String absolutePath = externalStorageDirectory.getAbsolutePath();
            path = absolutePath + path;
        }

        OKHttpUtils.getInstance().get(updateUrl, map, new NetCallBack() {
            @Override
            public void onSuccess(Object o) {
                if (o instanceof MessageBean) {
                    MessageBean info = (MessageBean) o;
                    if (info != null) {
                        if (info.isSuccess()) {
                            MessageBean.ResultBean result1 = info.getResult();

                            final MessageBean.ResultBean result = info.getResult();
                            // 有更新
                            if (result.isHasnewversion()) {
                                boolean isMust = result.isMustupdate();
                                AlertDialog.Builder builder = new AlertDialog.Builder(MainActivity.this);
                                builder.setTitle("更新提示")
                                        .setMessage(isMust ? "需要立即更新" : "是否需要更新")
                                        .setPositiveButton("更新", new DialogInterface.OnClickListener() {
                                            @Override
                                            public void onClick(DialogInterface dialogInterface, int i) {
                                                tv_pro.setVisibility(View.VISIBLE);
                                                progressBar.setVisibility(View.VISIBLE);
                                                String url = result.getUrl();

                                                // http://www.wuxirui.com/download/jinritoutiao.apk
                                                if (url.contains(".")) {
                                                    String typeName = url.substring(url.lastIndexOf(".") + 1);
                                                    if (url.contains("/")) {
                                                        String filename = url.substring(url.lastIndexOf("/") + 1, url.lastIndexOf("."));
                                                        path = path + filename + "." + typeName;
                                                    }
                                                }

                                                // 下载
                                                download(result.getUrl(), new File(path), new DownLoadListener() {
                                                    @Override
                                                    public void success(String path) {
                                                        Log.i(TAG, "success: " + path);
                                                        // 启动自动安装
                                                        installApk(new File(path));
                                                    }

                                                    @Override
                                                    public void failed(Exception e) {
                                                        Log.e(TAG, "failed: " + e.getMessage());
                                                    }

                                                    @Override
                                                    public void progress(long progress) {
                                                        Log.i(TAG, "progress: " + progress);
                                                        handler.sendEmptyMessageDelayed((int) progress, 1000);
                                                    }
                                                });
                                            }
                                        });
                                if (!isMust) {
                                    builder.setNegativeButton("稍候", new DialogInterface.OnClickListener() {
                                        @Override
                                        public void onClick(DialogInterface dialogInterface, int i) {

                                        }
                                    });
                                }

                                builder.create().show();
                            }

                        }
                    }
                }
            }

            @Override
            public void onFailed(Exception e) {

            }
        }, MessageBean.class);
    }

    private void download(String url, File file, DownLoadListener listener) {
        OKHttpUtils.getInstance().download(url, file, listener);
    }

    /**
     * 安装apk
     *
     * @param file
     */
    private void installApk(File file) {
        Intent intent = new Intent();
        intent.setAction(Intent.ACTION_VIEW);
        intent.addCategory("android.intent.category.DEFAULT");
        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        intent.setDataAndType(Uri.fromFile(file), "application/vnd.android.package-archive");
        startActivity(intent);
        android.os.Process.killProcess(android.os.Process.myPid());
    }
}
布局文件:

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.bwie.com.myapplication.MainActivity">

    <Button
        android:id="@+id/btn"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="检测版本更新"
        />

    <ProgressBar
        android:id="@+id/progressBar"
        style="?android:attr/progressBarStyleHorizontal"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_below="@+id/btn"
        android:layout_marginTop="45dp"
        android:max="100"
        android:visibility="gone"
        android:progress="0"
        />
    <TextView
        android:id="@+id/tv_pro"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="0%"
        android:layout_below="@+id/progressBar"
        android:layout_centerHorizontal="true"
        android:visibility="gone"
        />


</RelativeLayout>



猜你喜欢

转载自blog.csdn.net/xy8199/article/details/78927892