首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >Android版本更新知识(检测、升级,6.0,7.0,8.0)总结

Android版本更新知识(检测、升级,6.0,7.0,8.0)总结

作者头像
圆号本昊
发布2021-09-24 12:22:13
发布2021-09-24 12:22:13
1.1K0
举报
文章被收录于专栏:github@hornhuanggithub@hornhuang

更新 app 需要的下载 .apk 文件,实现的方法很多,如使用 okHttp 下载,Bmob 用户可以根据分装方法下载,这里为了方便大家我使用 Java.net 的 HttpURLConnection 接口进行下载

这里为了方便大家学习,先给出 github 上的 demo 地址:

https://github.com/FishInWater-1999/android_plan_material_design


这里我先给出实现版本检测、更新功能的活动之完整代码

在对其特俗部分详解


VersionControlActivity

代码语言:javascript
复制
public class VersionControlActivity extends AppCompatActivity {

    private static final int REQUEST_EXTERNAL_STORAGE = 1;
    private static String[] PERMISSIONS_STORAGE = {
            Manifest.permission.READ_EXTERNAL_STORAGE,
            Manifest.permission.WRITE_EXTERNAL_STORAGE
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_version_control);
        //在页面上显示版本信息
        TextView tv_versionName = findViewById(R.id.tv_versionName);
        try {
            tv_versionName.setText("版本名:" + getVersionName());
        } catch (Exception e) {
            e.printStackTrace();
        }

        int permission = ActivityCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE);
        if (permission != PackageManager.PERMISSION_GRANTED) {// api 23+ 您需要请求读/写权限,即使它们已经在您的清单中。
            // We don't have permission so prompt the user
            ActivityCompat.requestPermissions(
                    this,
                    PERMISSIONS_STORAGE,
                    REQUEST_EXTERNAL_STORAGE
            );
        }
    }

    //检测本程序的版本,这里假设从服务器中获取到最新的版本号为3
    public void checkVersion(View view) {
        //如果检测本程序的版本号小于服务器的版本号,那么提示用户更新
        if (getVersionCode() < 3) {// 三是范例 你需要在服务器上存储你版本的信息,以 json 形式获得后比较
            showDialogUpdate();//弹出提示版本更新的对话框

        }else{
            //否则吐司,说现在是最新的版本
            Toast.makeText(this,"当前已经是最新的版本",Toast.LENGTH_SHORT).show();

        }
    }

    /**
     * 提示版本更新的对话框
     */
    private void showDialogUpdate() {
        // 这里的属性可以一直设置,因为每次设置后返回的是一个builder对象
        AlertDialog.Builder builder = new AlertDialog.Builder(this);
        // 设置提示框的标题
        builder.setTitle("版本升级").
                // 设置提示框的图标
                        setIcon(R.mipmap.ic_launcher).
                // 设置要显示的信息
                        setMessage("发现新版本!请及时更新").
                // 设置确定按钮
                        setPositiveButton("确定", new DialogInterface.OnClickListener() {

                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        //Toast.makeText(MainActivity.this, "选择确定哦", 0).show();
                        loadNewVersionProgress();//下载最新的版本程序
                    }
                }).

                // 设置取消按钮,null是什么都不做,并关闭对话框
                        setNegativeButton("取消", null);

        // 生产对话框
        AlertDialog alertDialog = builder.create();
        // 显示对话框
        alertDialog.show();


    }

    /**
     * 下载新版本程序
     */
    private void loadNewVersionProgress() {
        final String uri="http://47.107.132.227/CETX";//发送该请求则从服务器下载
        final ProgressDialog pd;    //进度条对话框
        pd = new  ProgressDialog(this);
        pd.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
        pd.setMessage("正在下载更新");
        pd.show();
        //启动子线程下载任务
        new Thread(){
            @Override
            public void run() {
                try {
                    File file = getFileFromServer(uri, pd);
                    sleep(3000);
                    installApk(file);
                    pd.dismiss(); //结束掉进度条对话框
                } catch (Exception e) {
                    Log.d("123123", e.getMessage());
                    //下载apk失败
//                    Toast.makeText(getApplicationContext(), "下载新版本失败", Toast.LENGTH_LONG).show();
                    e.printStackTrace();
                }
            }}.start();
    }

    /**
     * 安装apk
     */
    private void installApk(final File file) {
        new Thread(){
            @Override
            public void run() {
                if (file != null) {
                    if(Build.VERSION.SDK_INT>=24) {//判读版本是否在7.0以上
                        Uri apkUri = FileProvider.getUriForFile(getApplicationContext(), "com.csti.cetx.fileProvider", file);//在AndroidManifest中的android:authorities值
                        Intent install = new Intent(Intent.ACTION_VIEW);
                        install.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);// 一定要记得 先 setFlags 在 addFlags 否则 set 会覆盖 add
                        install.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);//添加这一句表示对目标应用临时授权该Uri所代表的文件
                        install.setDataAndType(apkUri, "application/vnd.android.package-archive");
                        try {
                            sleep(3000);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                        startActivity(install);
                    } else{
                        Intent install = new Intent(Intent.ACTION_VIEW);
                        install.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                        install.setDataAndType(Uri.fromFile(file), "application/vnd.android.package-archive");
                        try {
                            sleep(3000);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                        startActivity(install);
                    }
                }
            }
        }.start();
    }


    /**
     * 从服务器获取apk文件的代码
     * 传入网址uri,进度条对象即可获得一个File文件
     * (要在子线程中执行哦)
     */
    public static File getFileFromServer(String uri, ProgressDialog pd) throws Exception{
        //如果相等的话表示当前的sdcard挂载在手机上并且是可用的
        if(Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)){
            URL url = new URL(uri);
            HttpURLConnection conn =  (HttpURLConnection) url.openConnection();
            conn.setConnectTimeout(5000);
            //获取到文件的大小
            pd.setMax(conn.getContentLength());
            InputStream is = conn.getInputStream();
            long time= System.currentTimeMillis();//当前时间的毫秒数
            File file = new File(Environment.getExternalStorageDirectory(), time+"CETX.apk");
            FileOutputStream fos = new FileOutputStream(file);
            BufferedInputStream bis = new BufferedInputStream(is);
            byte[] buffer = new byte[1024];
            int len ;
            int total=0;
            while((len =bis.read(buffer))!=-1){
                fos.write(buffer, 0, len);
                total+= len;
                //获取当前下载量
                pd.setProgress(total);
            }
            fos.close();
            bis.close();
            is.close();
            return file;
        }
        else{
            return null;
        }
    }


    /*
     * 获取当前程序的版本名
     */
    private String getVersionName() throws Exception {
        //获取packagemanager的实例
        PackageManager packageManager = getPackageManager();
        //getPackageName()是你当前类的包名,0代表是获取版本信息
        PackageInfo packInfo = packageManager.getPackageInfo(getPackageName(), 0);
        Log.e("TAG", "版本号" + packInfo.versionCode);
        Log.e("TAG", "版本名" + packInfo.versionName);
        return packInfo.versionName;

    }


    /*
     * 获取当前程序的版本号
     */
    private int getVersionCode() {
        try {

            //获取packagemanager的实例
            PackageManager packageManager = getPackageManager();
            //getPackageName()是你当前类的包名,0代表是获取版本信息
            PackageInfo packInfo = packageManager.getPackageInfo(getPackageName(), 0);
            Log.e("TAG", "版本号" + packInfo.versionCode);
            Log.e("TAG", "版本名" + packInfo.versionName);
            return packInfo.versionCode;

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

        }

        return  1;
    }

}

具体功能代码里已经很清楚了,这里说下 Android 7.0 以后,Android 7.0 为了提高私有目录的安全性,防止应用信息的泄漏,从 Android 7.0 开始,应用私有目录的访问权限被做限制。具体表现为,开发人员不能够再简单地通过 file:// URI 访问其他应用的私有目录文件或者让其他应用访问自己的私有目录文件。

所以这里我们引入了 fileProvider 的概念,作为四大组件之一的 ContentProvider,一直扮演着应用间共享资源的角色。这里我们要使用到的 FileProvider,就是 ContentProvider 的一个特殊子类,帮助我们将访问受限的 file:// URI 转化为可以授权共享的 content:// URI。


第一步,注册一个 FileProvider

代码语言:javascript
复制

第二步,添加共享目录

在 res/xml 目录下新建一个 provider_paths 文件,用于存放应用需要共享的目录文件。这个 provider_paths 文件的内容类似这样:( 注:path 里为空即可 )

代码语言:javascript
复制
  • :内部存储空间应用私有目录下的 files/ 目录,等同于 Context.getFilesDir() 所获取的目录路径;
  • :内部存储空间应用私有目录下的 cache/ 目录,等同于 Context.getCacheDir() 所获取的目录路径;
  • :外部存储空间根目录,等同于 Environment.getExternalStorageDirectory() 所获取的目录路径;
  • :外部存储空间应用私有目录下的 files/ 目录,等同于 Context.getExternalFilesDir(null) 所获取的目录路径;
  • :外部存储空间应用私有目录下的 cache/ 目录,等同于 Context.getExternalCacheDir();

生产 Uri

在完整代码中,我们先对用户手机 Android 的版本进行判断:如果在不在 7.0 及以上,则不需要通过 fileProvider 访问,如果在 7.0 及已上咱通过 getUriForFile 方法生成 Uri

代码语言:javascript
复制
Uri apkUri = FileProvider.getUriForFile(getApplicationContext(), "你的包名.fileProvider", file);//在AndroidManifest中的android:authorities值
代码语言:javascript
复制
new Thread(){
    @Override
    public void run() {
        if (file != null) {
            if(Build.VERSION.SDK_INT>=24) {//判读版本是否在7.0以上
                Uri apkUri = FileProvider.getUriForFile(getApplicationContext(), "com.csti.cetx.fileProvider", file);//在AndroidManifest中的android:authorities值
                Intent install = new Intent(Intent.ACTION_VIEW);
                install.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);// 一定要记得 先 setFlags 在 addFlags 否则 set 会覆盖 add
                install.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);//添加这一句表示对目标应用临时授权该Uri所代表的文件
                install.setDataAndType(apkUri, "application/vnd.android.package-archive");
                try {
                    sleep(3000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                startActivity(install);
            } else{
                Intent install = new Intent(Intent.ACTION_VIEW);
                install.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                install.setDataAndType(Uri.fromFile(file), "application/vnd.android.package-archive");
                try {
                    sleep(3000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                startActivity(install);
            }
        }
    }
}.start();

别忘了加上权限哦

代码语言:javascript
复制
    // 8.0

如有疑问欢迎在评论区留言,也欢迎关注我获得更多姿势。

关于 8.0 请看这位大神的解析

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2019/05/24 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 这里我先给出实现版本检测、更新功能的活动之完整代码
  • 在对其特俗部分详解
  • VersionControlActivity
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档