Android 实现一个检查版本更新功能(适配到8.0+)

          作为一个app,如果要长期使用,我们是要对它的版本进行更新迭代的,记录一下,网上参考一个一下别人的检查更新的做法,然后自己修改成自己需要的。

我们可以看一些效果图:

 

 

 

   以上是效果图

 

 

   我们还是看回自己的代码,布局那些就不放上来了,自己可以随便撸一个自己喜欢的样式出来。

这个是我的检查更新按钮:

   case R.id.ll_auto_update:
               //更新方法
                auto_update();
                break;

   1.auto_update()这个方法里,我去调用服务器上有apk 的接口,请求获得返回  版本号信息,apk下载链接,版本内容介绍。(代码不可以复制使用,可以参考),重要的是拿到接口返回来的apk下载链接

 

   //更新版本信息
    private void auto_update() {
        String url = "XXXXXXXXXXXXXX";
        //获取本地内部版本好
        final int vcode = PackageUtils.getVersionCode(getContext());
        Map<String, String> map = new HashMap<>();
        map.put("XXXXX", "XXXXX");
      //调用封装好的网络请求,返回json格式
        OkHttpRequest.getInstance().getRequest(url, map, getContext(), new Handler() {
            @Override
            public void handleMessage(Message msg) {
                super.handleMessage(msg);

                try {
                    ResponseModer responseModer = (ResponseModer) msg.obj;
                    JSONObject jsonObject = responseModer.getJsonResultData();
                    System.out.println("asdad" + jsonObject);
                   String version = jsonObject.getString("version");
                   //重要的是拿到下载apk链接
                   String update_url = jsonObject.getString("update_url");
                   int verion_int = jsonObject.getInt("verion_int");
                   String ver_introduction = jsonObject.getString("ver_introduction");
                    System.out.println("外部版本号==" + version);
                    System.out.println("下载链接==" + update_url);
                    System.out.println("内部版本号==" + verion_int);
                    System.out.println("版本介绍==" + ver_introduction);
                    if (verion_int <= vcode) {
                        Util.showToast(getContext(), "现在是最新的版本");
                    } else {
                        // Util.showToast(getContext(), "检查到有新版本信息更新");
                        showUpdateDialog();
                    }
                } catch (JSONException e) {
                    e.printStackTrace();
                }

            }
        });

    }

这里面去获取当前apk的信息,拿到当前的版本信息,我是通过一个(PackageUtils)类去获取的。

  

public class PackageUtils {
    /**
     * 获取版本名称
     *
     * @param context 上下文
     *
     * @return 版本名称
     */
    public static String getVersionName(Context context) {

        //获取包管理器
        PackageManager pm = context.getPackageManager();
        //获取包信息
        try {
            PackageInfo packageInfo = pm.getPackageInfo(context.getPackageName(), 0);
            //返回版本号
            return packageInfo.versionName;
        } catch (PackageManager.NameNotFoundException e) {
            e.printStackTrace();
        }

        return null;

    }

    /**
     * 获取版本号
     *
     * @param context 上下文
     *
     * @return 版本号
     */
    public static int getVersionCode(Context context) {

        //获取包管理器
        PackageManager pm = context.getPackageManager();
        //获取包信息
        try {
            PackageInfo packageInfo = pm.getPackageInfo(context.getPackageName(), 0);
            //返回版本号
            return packageInfo.versionCode;
        } catch (PackageManager.NameNotFoundException e) {
            e.printStackTrace();
        }

        return 0;

    }

    /**
     * 获取App的名称
     *
     * @param context 上下文
     *
     * @return 名称
     */
    public static String getAppName(Context context) {
        PackageManager pm = context.getPackageManager();
        //获取包信息
        try {
            PackageInfo packageInfo = pm.getPackageInfo(context.getPackageName(), 0);
            //获取应用 信息
            ApplicationInfo applicationInfo = packageInfo.applicationInfo;
            //获取albelRes
            int labelRes = applicationInfo.labelRes;
            //返回App的名称
            return context.getResources().getString(labelRes);
        } catch (PackageManager.NameNotFoundException e) {
            e.printStackTrace();
        }

        return null;
    }
}

 

//获取本地内部版本号
final int vcode = PackageUtils.getVersionCode(getContext());

    跟服务器返回接口的内部版本号(verion_int ) 进行比较;

服务器上的内部版本号大于本地的时候,我们在去拿到apk下载链接 去执行下一步的操作。

2.showUpdateDialog();这个方法,来处理;

  

 /**
     * 点击下载弹框
     */
    private void showUpdateDialog() {
        AlertDialog.Builder builder = new AlertDialog.Builder(getContext());
        builder.setTitle("检测到新版本");
        builder.setMessage("版本介绍:\n" + ver_introduction);
        builder.setPositiveButton("以后再说", new DialogInterface.OnClickListener() {

            @Override
            public void onClick(DialogInterface dialog, int which) {

            }
        }).setNegativeButton("立即更新", new DialogInterface.OnClickListener() {

            @Override
            public void onClick(DialogInterface dialog, int which) {
                showDownloadDialog();
            }
        });
        builder.show();
    }

弹出窗提示,版本介绍内容,当点击立即更新时,我们再进去下一步的下载操作。

3.showDownloadDialog(); 下载进度;

 /*
     * 显示正在下载对话框
     */
    protected void showDownloadDialog() {
        AlertDialog.Builder builder = new AlertDialog.Builder(getContext());
        builder.setTitle("下载中");
        View view = LayoutInflater.from(getContext()).inflate(R.layout.dialog_progress, null);
        mProgressBar = view.findViewById(R.id.id_progress);
        builder.setView(view);

        builder.setNegativeButton("取消", new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int which) {
                // 隐藏当前对话框
                dialog.dismiss();
                // 设置下载状态为取消
                mIsCancel = true;
            }
        });

        mDownloadDialog = builder.create();
        mDownloadDialog.show();

        // 下载文件
        downloadAPK();
    }

    /* 开启新线程下载apk文件
     */
    private void downloadAPK() {

        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    mIsCancel = false;
                    if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
                        String sdPath = Environment.getExternalStorageDirectory() + "/";
//                      文件保存路径
                        mSavePath = sdPath + "lianzhandownload";
                        File dir = new File(mSavePath);
                        if (!dir.exists()) {
                            dir.mkdir();
                        }
                        // 下载文件
                        HttpURLConnection conn = (HttpURLConnection) new URL(update_url).openConnection();
                        conn.connect();
                        InputStream is = conn.getInputStream();
                        int length = conn.getContentLength();

                        File apkFile = new File(mSavePath, version);
                        FileOutputStream fos = new FileOutputStream(apkFile);

                        int count = 0;
                        byte[] buffer = new byte[1024];

                        while (!mIsCancel) {
                            int numread = is.read(buffer);
                            count += numread;
                            // 计算进度条的当前位置
                            mProgress = (int) (((float) count / length) * 100);
                            // 更新进度条
                            mUpdateProgressHandler.sendEmptyMessage(1);

                            // 下载完成
                            if (numread < 0) {
                                mUpdateProgressHandler.sendEmptyMessage(2);
                                break;
                            }
                            fos.write(buffer, 0, numread);
                        }
                        fos.close();
                        is.close();
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }).start();
    }

   开启线程介绍;下载进度更新ui显示:

 /**
     * 接收消息
     */
    private Handler mUpdateProgressHandler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
                case 1:
                    // 设置进度条
                    mProgressBar.setProgress(mProgress);
                    break;
                case 2:
                    // 隐藏当前下载对话框
                    mDownloadDialog.dismiss();
                    // 安装 APK 文件
                    installAPK();
            }
        }
    };

 当下载完成之后,我们再去安装新版的apk:

 我们要注意文件清单添加相应的权限:

  <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" />
  <uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES"/>

    如果没有添加到最后一条的权限,8.0下载完不会跳转获取apk安装。安装之前还要做一下的处理https://blog.csdn.net/zhaihaohao1/article/details/81809110参考别人的方法。

4。 installAPK()方法;

/*
     * 下载到本地后执行安装
     */
    protected void installAPK() {
        File apkFile = new File(mSavePath, version);
        if (!apkFile.exists()) {
            return;
        }


        Intent intent = new Intent(Intent.ACTION_VIEW);
        //判断是否是AndroidN以及更高的版本
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
            intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
            Uri contentUri = FileProvider.getUriForFile(getContext(), BuildConfig.APPLICATION_ID + ".fileProvider", apkFile);
            intent.setDataAndType(contentUri, "application/vnd.android.package-archive");
        } else {
            intent.setDataAndType(Uri.fromFile(apkFile), "application/vnd.android.package-archive");
            intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        }
        getActivity().startActivity(intent);
    }

 

 文件清单多加

 

  <provider
            android:name="android.support.v4.content.FileProvider"
            android:authorities="包名.fileProvider"
            android:grantUriPermissions="true"
            android:exported="false">
            <meta-data
                android:name="android.support.FILE_PROVIDER_PATHS"
                android:resource="@xml/file_paths" />
        </provider>

 

 

3、打开file_paths.xml文件添加如下内容

<?xml version="1.0" encoding="utf-8"?>
<paths>
    <external-path="包名/" name="fileProvider" />
    <external-path path="." name="apk下载文件夹名" />
</paths>

path:需要临时授权访问的路径(.代表所有路径) 
name:就是你给这个访问路径起个名字 

然后再去调用installAPK()。到这里就基本上就可以了。这是我修改了部分代码。如果你还是看不懂,你可以参考下别人的

https://blog.csdn.net/zhaihaohao1/article/details/81808902

、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、2020.4.28重新补充善、、、、、、、、、、、 

1.上面弹窗提示,修改自定义的布局弹窗,效果如下:

 

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content">

    <TextView
        android:id="@+id/tv_01"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_margin="15dp"
        android:text="@string/up_titletips"
        android:textColor="@color/black"
        android:textSize="32sp" />

    <View
        android:id="@+id/vv"
        android:layout_width="match_parent"
        android:layout_height="2dp"
        android:layout_below="@id/tv_01"
        android:background="@color/lightpink" />

    <LinearLayout
        android:id="@+id/ll_01"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_below="@id/vv"
        android:layout_margin="25dp"
        android:orientation="horizontal">

        <RelativeLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_weight="1.8"
            android:visibility="gone">

            <RelativeLayout
                android:layout_width="134dp"
                android:layout_height="134dp"
                android:layout_alignParentTop="true"
                android:layout_centerHorizontal="true"
                android:background="@drawable/ic_launcher_background">

                <ImageView
                    android:id="@+id/detect_reg_image_item"
                    android:layout_width="134dp"
                    android:layout_height="134dp"
                    android:layout_centerHorizontal="true"
                    android:layout_centerVertical="true"
                    android:src="@mipmap/ic_launcher" />

            </RelativeLayout>


        </RelativeLayout>

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginLeft="20dp"
            android:layout_weight="1"
            android:orientation="vertical">


            <LinearLayout
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_weight="1"
                android:orientation="horizontal">

                <TextView
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:text="@string/up_versionexpian"
                    android:textColor="@color/lightpink"
                    android:textSize="28sp" />

                <TextView
                    android:id="@+id/tv_username"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:textColor="#FFFFFF"
                    android:textSize="20sp" />

            </LinearLayout>

            <LinearLayout
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_marginTop="20dp"
                android:layout_weight="1"
                android:orientation="horizontal">

                <TextView
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:text="@string/up_versionexpian"
                    android:textColor="#FFFFFF"
                    android:textSize="28sp" />

                <TextView
                    android:id="@+id/tv_info"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:text="测试123"
                    android:textColor="@color/lightpink"
                    android:textSize="28sp" />

            </LinearLayout>
        </LinearLayout>


    </LinearLayout>

    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_margin="15dp"
        android:layout_below="@id/ll_01">

        <Button

            android:id="@+id/btn_EXIT"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignParentRight="true"
            android:text="@string/up_neglet"
            android:textColor="@color/black"
            android:textSize="30sp" />

        <Button
            android:id="@+id/btn_OK"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginRight="15dp"
            android:layout_toLeftOf="@id/btn_EXIT"
            android:text="@string/up_installnow"
            android:textColor="@color/black"
            android:textSize="30sp" />

    </RelativeLayout>
</RelativeLayout>
   /**
     * 弹框处理事件,info:传入版本介绍
     */
    private void init_dialog(String info) {
        AlertDialog.Builder customizeDialog =
                new AlertDialog.Builder(TestFrag_ShowhidedActivity.this);
        final View dialogView = LayoutInflater.from(TestFrag_ShowhidedActivity.this)
                .inflate(R.layout.layout_upappdialog, null);
        customizeDialog.setView(dialogView);
        TextView tv_info = (TextView) dialogView.findViewById(R.id.tv_info);


        Button btn_OK = dialogView.findViewById(R.id.btn_OK);
        Button btn_EXIT = dialogView.findViewById(R.id.btn_EXIT);
        // 图片展示Uri.fromFile

        tv_info.setText(info);

        final AlertDialog dialog = customizeDialog.show();
        Window window = dialog.getWindow();
        window.setGravity(Gravity.CENTER);
        customizeDialog.create();
        btn_OK.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                dialog.dismiss();
                showDownloadDialog();
            }
        });

        btn_EXIT.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                dialog.dismiss();
            }
        });
    }

2.当点击立即更新按钮之后,跳转到进度条显示:

 

进度布局:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <ProgressBar
        android:id="@+id/progressBar"
        style="?android:attr/progressBarStyleHorizontal"
        android:layout_width="match_parent"
        android:layout_height="30dp" />

    <RelativeLayout
        android:layout_width="wrap_content"
        android:layout_height="wrap_content">
        <TextView
            android:id="@+id/tv_downloadnum"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignParentRight="true"
            android:text="0%"
            android:textSize="30dp"
            android:layout_margin="20dp"
            android:textColor="@color/black" />
    </RelativeLayout>


</LinearLayout>

 

 

   /*
     * 显示正在下载对话框
     */
    protected void showDownloadDialog() {
        AlertDialog.Builder builder = new AlertDialog.Builder(TestFrag_ShowhidedActivity.this);
        builder.setTitle("下载中");
        View view = LayoutInflater.from(getApplicationContext()).inflate(R.layout.dialog_progress, null);
        mProgressBar = view.findViewById(R.id.progressBar);
        tv_downloadnum = view.findViewById(R.id.tv_downloadnum);
        builder.setView(view);
        builder.setNegativeButton("取消", new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int which) {
                // 隐藏当前对话框
                dialog.dismiss();
                // 设置下载状态为取消
                mIsCancel = true;
            }
        });

        mDownloadDialog = builder.create();
        mDownloadDialog.show();

        // 下载文件,g跟第一步的方法一下,找到下载好的文件存放路径,执行跳转安装即可
        downloadAPK();   
    }
    private void downloadAPK() {
      File file=new File(download);
      if(!file.exists()){
          file.mkdirs();
      }

        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    mIsCancel = false;
                    // 下载文件
                    HttpURLConnection conn = (HttpURLConnection) new URL(url).openConnection();
                    conn.connect();
                    InputStream is = conn.getInputStream();
                    int length = conn.getContentLength();
                    // url_version + ".apk",自己定义的apK名称
                    File apkFile = new File(download, url_version + ".apk");
                    FileOutputStream fos = new FileOutputStream(apkFile);

                    int count = 0;
                    byte[] buffer = new byte[1024];

                    while (!mIsCancel) {
                        int numread = is.read(buffer);
                        count += numread;
                        // 计算进度条的当前位置
                        mProgress = (int) (((float) count / length) * 100);
                        // 更新进度条
                        init_message(68, String.valueOf(mProgress));

                        // 下载完成
                        if (numread < 0) {
                            handler.sendEmptyMessage(69);
                            break;
                        }
                        fos.write(buffer, 0, numread);
                    }
                    fos.close();
                    is.close();

                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }).start();
    }

   //线程
    private void init_message(int num, String str) {
        Message message = handler.obtainMessage();
        message.what = num;
        message.obj = str;
        handler.sendMessage(message);
    }

对应线程68显示进度条百分之几,   69 执行安装:

    case 68:
                    // 设置进度条
                    mProgressBar.setProgress(mProgress);
                    String num = String.valueOf(msg.obj);
                    Log.i(TAG, "handleMessage: 进度啊=" + num);
                    tv_downloadnum.setText(num + "%");
                    break;
                case 69:
                    // 隐藏当前下载对话框
                    mDownloadDialog.dismiss();
                    // 安装 APK 文件
                    installAPK();
                   /* Intent intent= IntentUtil.installAPK(TestFrag_ShowhidedActivity.this,download+ File.separator +url_version + ".apk");
                    startActivity(intent);*/
                    Log.i(TAG, "handleMessage: 安装啊");
                    break;

 备注:一些定义全局变量名称

private ProgressBar mProgressBar;
private volatile boolean mIsCancel = false;
//  进度
private int mProgress;
private TextView tv_downloadnum;

 这次补充和新增一些弹框优化,总体的核心步骤没变化,根据后台接口的定义返回的url去下载apk,存在本地,当下载完成就调用Intent意图去找到apk文件uri地址,执行手动确定安装。

       每个人的需求不一定相同,但大致的方向还是一样的,我们可以参考别的踩过的坑,避免再去踩,当然目前这样的方式还是多少会存在不足,但我们可以实现之前,有了大致的思路,我们再去深入学习探讨,这样的学习方式也是不错的,由于本人知识有限,上面的东西没过多的详细说明,只是简单的说明。如有什么问题,可在评论区留意,我们一起探讨学习,谢谢。

 

评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值