zoukankan      html  css  js  c++  java
  • AppUtils【获取手机的信息和应用版本号、安装apk】

    版权声明:本文为HaiyuKing原创文章,转载请注明出处!

    前言

    一个获取设备的系统版本号、设备的型号、应用版本号code值、应用版本号name值、包名、是否更新、安装apk的工具类。

    其实这个工具类的主要功能是安装apk方法,所以需要搭配《Android6.0运行时权限(基于RxPermission开源库)》、《AppDir【创建缓存目录】》【这个是用来存放下载的apk文件的,可以不用】。

    下载apk的过程没有使用网路请求,而是通过模拟的方式:其实就是从assets目录复制apk文件到手机目录中。

    效果图

     

    代码分析

    需要注意的代码包括以下部分:

    1、下载apk之前需要先申请运行时权限(READ_EXTERNAL_STORAGE),我是在项目启动的时候申请的,不是在事件触发的时候申请的;

    2、适配7.0FileProvider

    3、安装前先适配8.0请求未知来源权限

    使用步骤

    一、项目组织结构图

    注意事项:

    1、  导入类文件后需要change包名以及重新import R文件路径

    2、  Values目录下的文件(strings.xml、dimens.xml、colors.xml等),如果项目中存在,则复制里面的内容,不要整个覆盖

    二、导入步骤

    将AppUtils复制到项目中

    package com.why.project.apputilsdemo.util;
    
    import android.content.Context;
    import android.content.Intent;
    import android.content.pm.PackageInfo;
    import android.content.pm.PackageManager;
    import android.net.Uri;
    import android.os.Build;
    import android.support.v4.content.FileProvider;
    import android.text.TextUtils;
    
    import java.io.File;
    
    /**
     * 获取手机的信息和应用版本号、安装apk
     */
    public class AppUtils {
    
        /**
         * 获取设备的系统版本号
         */
        public static String getDeviceVersion() {
            return android.os.Build.VERSION.RELEASE;
        }
    
        /**
         * 获取设备的型号
         */
        public static String getDeviceName() {
            String model = android.os.Build.MODEL;
            return model;
        }
    
        /**
         * 应用版本号code值
         */
        public static int getVersionCode(Context context) {
            return getPackageInfo(context).versionCode;
        }
        /**
         * 应用版本号name值
         */
        public static String getVersionName(Context context){
            return getPackageInfo(context).versionName;
        }
    
        private static PackageInfo getPackageInfo(Context context) {
            PackageInfo pi = null;
    
            try {
                PackageManager pm = context.getPackageManager();
                pi = pm.getPackageInfo(context.getPackageName(),
                        PackageManager.GET_CONFIGURATIONS);
                return pi;
            } catch (Exception e) {
                e.printStackTrace();
            }
            return pi;
        }
    
        //获取包名
        public static String getPackageName(Context context){
            return context.getPackageName();
        }
    
        //是否更新,根据versionName值进行判断
        public static boolean getVersionUpdate(Context context, String versionNameServer){
            //versionNameServer = "3.1";
            String versionNameLocal = getVersionName(context);
            if(!TextUtils.isEmpty(versionNameLocal) && !TextUtils.isEmpty(versionNameServer)){
                String[] splitLocal = versionNameLocal.split("\.");
                String[] splitServer = versionNameServer.split("\.");
                if(splitLocal.length == splitServer.length){
                    for(int i=0;i<splitLocal.length;i++){
                        int localInt = Integer.parseInt(splitLocal[i]);
                        int serverInt = Integer.parseInt(splitServer[i]);
                        if(serverInt > localInt){
                            return true;
                        }else if(serverInt==localInt){
                        }
                        else {
                            return false;
                        }
                    }
                }
            }
            return false;
        }
    
        /**返回安装apk的Intent*/
        public static Intent getFileIntent(Context mContext,String fileSavePath) {
            File apkfile = new File(fileSavePath);
            if (!apkfile.exists()) {
                return null;
            }
            Intent intent = new Intent();
            intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
            intent.setAction(android.content.Intent.ACTION_VIEW);
    
            Uri uri;
            if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
                String authority = mContext.getApplicationInfo().packageName + ".provider";
                uri = FileProvider.getUriForFile(mContext.getApplicationContext(), authority, apkfile);
                intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);//添加这一句表示对目标应用临时授权该Uri所代表的文件【很重要】
            } else {
                uri = Uri.fromFile(apkfile);
            }
            intent.setDataAndType(uri, getMIMEType(apkfile));
            return intent;
        }
    
        public static String getMIMEType(File file) {
            String type = null;
            String suffix = file.getName().substring(file.getName().lastIndexOf(".") + 1, file.getName().length());
            if (suffix.equals("apk")) {
                type = "application/vnd.android.package-archive";
            } else {
                // /*如果无法直接打开,就跳出软件列表给用户选择 */
                type = "*/*";
            }
            return type;
        }
    
        /**
         * 安装apk【如果项目中需要使用这个方法的话,需要申请运行时权限(读写文件的权限)、需要特出处理Android8.0的请求未知来源权限】
         */
        public static void installApk(Context mContext,String fileSavePath) {
            Intent intent = getFileIntent(mContext,fileSavePath);
            if(intent != null){
                mContext.startActivity(intent);
            }
        }
    }
    AppUtils.java

    在AndroidManifest.xml中添加权限以及配置7.0FileProvider【注意:provider中的android:authorities值:${applicationId}.provider,其中${applicationId}代表的真实值就是APP的build.gradle中的applicationId(包名)值】

    <?xml version="1.0" encoding="utf-8"?>
    <manifest xmlns:android="http://schemas.android.com/apk/res/android"
              package="com.why.project.apputilsdemo">
    
        <!-- =================AppDir用到的权限========================== -->
        <!-- 允许程序读取外部存储文件 -->
        <!--<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>-->
        <!-- 允许程序写入外部存储,如SD卡上写文件 -->
        <!--<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"></uses-permission>-->
    
        <!-- =================AppUtils用到的权限========================== -->
        <!-- 允许程序读取外部存储文件 -->
        <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
        <!-- 允许程序写入外部存储,如SD卡上写文件 -->
        <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"></uses-permission>
        <!-- =================8.0安装apk需要请求未知来源权限========================== -->
        <uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES"/>
    
        <application
            android:allowBackup="true"
            android:icon="@mipmap/ic_launcher"
            android:label="@string/app_name"
            android:roundIcon="@mipmap/ic_launcher_round"
            android:supportsRtl="true"
            android:theme="@style/AppTheme">
    
            <!-- =================7.0上读取文件========================== -->
            <!--参考资料https://blog.csdn.net/lmj623565791/article/details/72859156-->
            <!--authorities:{app的包名}.provider
            grantUriPermissions:必须是true,表示授予 URI 临时访问权限
            exported:必须是false
            resource:中的@xml/provider_paths是我们接下来要添加的文件-->
            <provider
                android:name="android.support.v4.content.FileProvider"
                android:authorities="${applicationId}.provider"
                android:exported="false"
                android:grantUriPermissions="true">
                <meta-data android:name="android.support.FILE_PROVIDER_PATHS"
                           android:resource="@xml/provider_paths"/>
            </provider>
    
            <activity android:name=".MainActivity">
                <intent-filter>
                    <action android:name="android.intent.action.MAIN"/>
    
                    <category android:name="android.intent.category.LAUNCHER"/>
                </intent-filter>
            </activity>
        </application>
    
    </manifest>

    将provider_paths文件复制到项目的res/xml目录下【适配7.0FileProvider】

    <?xml version="1.0" encoding="utf-8"?>
    <!--参考资料https://blog.csdn.net/lmj623565791/article/details/72859156-->
    <!--<root-path/> 代表设备的根目录new File("/");-->
    <!--<files-path/> 代表context.getFilesDir()-->
    <!--<cache-path/> 代表context.getCacheDir()-->
    <!--<external-path/> 代表Environment.getExternalStorageDirectory()-->
    <!--<external-files-path>代表context.getExternalFilesDirs()-->
    <!--<external-cache-path>代表getExternalCacheDirs()-->
    
    <!--path:需要临时授权访问的路径(.代表所有路径)-->
    <!--name:就是你给这个访问路径起个名字-->
    <paths>
        <root-path name="root" path="." />
        <files-path name="files" path="." />
        <cache-path name="cache" path="." />
        <external-path name="external" path="." />
        <external-files-path name="external_file_path" path="." />
        <external-cache-path name="external_cache_path" path="." />
    </paths>

    参考《Android6.0运行时权限(基于RxPermission开源库)》、《AppDir【创建缓存目录】》导入相关文件。

    三、使用方法

    常规方法调用【获取设备型号、版本号、应用版本号、包名等】

    btn_show.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    String DeviceVersion = AppUtils.getDeviceVersion();
                    String DeviceName = AppUtils.getDeviceName();
                    int VersionCode = AppUtils.getVersionCode(MainActivity.this);
                    String VersionName = AppUtils.getVersionName(MainActivity.this);
                    String PackageName = AppUtils.getPackageName(MainActivity.this);
                    boolean isUpdate = AppUtils.getVersionUpdate(MainActivity.this,"2.0");
    
                    String showText = "设备的系统版本号:" + DeviceVersion +
                            "
    设备的型号:" + DeviceName +
                            "
    应用版本号code值:" + VersionCode +
                            "
    应用版本号name值:" + VersionName +
                            "
    包名:" + PackageName +
                            "
    是否更新(服务器版本号name值是2.0):" + isUpdate;
    
                    tv_show.setText(showText);
                }
            });

    申请运行时权限(存储权限)并模拟下载apk文件

    /**只有一个运行时权限申请的情况*/
        private void onePermission(){
            RxPermissions rxPermissions = new RxPermissions(MainActivity.this); // where this is an Activity instance
            rxPermissions.request(Manifest.permission.READ_EXTERNAL_STORAGE) //权限名称,多个权限之间逗号分隔开
                    .subscribe(new Consumer<Boolean>() {
                        @Override
                        public void accept(Boolean granted) throws Exception {
                            Log.e(TAG, "{accept}granted=" + granted);//执行顺序——1【多个权限的情况,只有所有的权限均允许的情况下granted==true】
                            if (granted) { // 在android 6.0之前会默认返回true
                                // 已经获取权限
                                Toast.makeText(MainActivity.this, "已经获取权限", Toast.LENGTH_SHORT).show();
                                downloadApkFile();
                            } else {
                                // 未获取权限
                                Toast.makeText(MainActivity.this, "您没有授权该权限,请在设置中打开授权", Toast.LENGTH_SHORT).show();
                            }
                        }
                    }, new Consumer<Throwable>() {
                        @Override
                        public void accept(Throwable throwable) throws Exception {
                            Log.e(TAG,"{accept}");//可能是授权异常的情况下的处理
                        }
                    }, new Action() {
                        @Override
                        public void run() throws Exception {
                            Log.e(TAG,"{run}");//执行顺序——2
                        }
                    });
        }
    
        /**模拟下载文件到手机本地目录下*/
        private void downloadApkFile(){
            String assetsFilePath = "wanandroid.apk";
            apkFileSavePath = AppDir.getInstance(MainActivity.this).DOWNLOAD + File.separator + "wanandroid.apk";
            DownloadUtil.copyOneFileFromAssetsToSD(MainActivity.this,assetsFilePath,apkFileSavePath);
        }

    安装apk(先适配Android8.0请求未知来源权限)

    /**
         * 检测版本8.0
         */
        public void checkOreo() {
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {//8.0
                //判断是否可以直接安装
                boolean canInstall = getPackageManager().canRequestPackageInstalls();
                if (!canInstall) {
                    RxPermissions rxPermissions = new RxPermissions(MainActivity.this); // where this is an Activity instance
                    rxPermissions.request(Manifest.permission.REQUEST_INSTALL_PACKAGES) //权限名称,多个权限之间逗号分隔开
                            .subscribe(new Consumer<Boolean>() {
                                @Override
                                public void accept(Boolean granted) throws Exception {
                                    Log.e(TAG, "{accept}granted=" + granted);//执行顺序——1【多个权限的情况,只有所有的权限均允许的情况下granted==true】
                                    if (granted) { // 在android 6.0之前会默认返回true
                                        //安装APP
                                        AppUtils.installApk(MainActivity.this, apkFileSavePath);
                                    } else {
                                        Intent intent = new Intent(Settings.ACTION_MANAGE_UNKNOWN_APP_SOURCES, Uri.parse("package:" + getPackageName()));
                                        startActivityForResult(intent, 1000);
                                    }
                                }
                            }, new Consumer<Throwable>() {
                                @Override
                                public void accept(Throwable throwable) throws Exception {
                                    Log.e(TAG,"{accept}");//可能是授权异常的情况下的处理
                                }
                            }, new Action() {
                                @Override
                                public void run() throws Exception {
                                    Log.e(TAG,"{run}");//执行顺序——2
                                }
                            });
                } else {
                    //安装APP
                    AppUtils.installApk(MainActivity.this,apkFileSavePath);
                }
            } else {
                //安装APP
                AppUtils.installApk(MainActivity.this,apkFileSavePath);
            }
        }
    
        @Override
        protected void onActivityResult(int requestCode, int resultCode, Intent data) {
            super.onActivityResult(requestCode, resultCode, data);
            switch (requestCode) {
                case 1000:
                    checkOreo();
                    break;
            }
        }

    完整代码:

    package com.why.project.apputilsdemo;
    
    import android.Manifest;
    import android.content.Intent;
    import android.net.Uri;
    import android.os.Build;
    import android.os.Bundle;
    import android.provider.Settings;
    import android.support.v7.app.AppCompatActivity;
    import android.util.Log;
    import android.view.View;
    import android.widget.Button;
    import android.widget.TextView;
    import android.widget.Toast;
    
    import com.tbruyelle.rxpermissions2.RxPermissions;
    import com.why.project.apputilsdemo.util.AppDir;
    import com.why.project.apputilsdemo.util.AppUtils;
    
    import java.io.File;
    
    import io.reactivex.functions.Action;
    import io.reactivex.functions.Consumer;
    
    public class MainActivity extends AppCompatActivity {
        private static final String TAG = MainActivity.class.getSimpleName();
    
        private Button btn_show;
        private Button btn_install;
        private TextView tv_show;
    
        String apkFileSavePath = "";
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    
            onePermission();//申请运行时权限(读写文件的权限)
    
            initViews();
            initEvents();
        }
    
        private void initViews() {
            btn_show = findViewById(R.id.btn_show);
            btn_install = findViewById(R.id.btn_install);
            tv_show = findViewById(R.id.tv_show);
        }
    
        private void initEvents() {
            btn_show.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    String DeviceVersion = AppUtils.getDeviceVersion();
                    String DeviceName = AppUtils.getDeviceName();
                    int VersionCode = AppUtils.getVersionCode(MainActivity.this);
                    String VersionName = AppUtils.getVersionName(MainActivity.this);
                    String PackageName = AppUtils.getPackageName(MainActivity.this);
                    boolean isUpdate = AppUtils.getVersionUpdate(MainActivity.this,"2.0");
    
                    String showText = "设备的系统版本号:" + DeviceVersion +
                            "
    设备的型号:" + DeviceName +
                            "
    应用版本号code值:" + VersionCode +
                            "
    应用版本号name值:" + VersionName +
                            "
    包名:" + PackageName +
                            "
    是否更新(服务器版本号name值是2.0):" + isUpdate;
    
                    tv_show.setText(showText);
                }
            });
    
            btn_install.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    checkOreo();
                }
            });
        }
    
        /**
         * 检测版本8.0
         */
        public void checkOreo() {
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {//8.0
                //判断是否可以直接安装
                boolean canInstall = getPackageManager().canRequestPackageInstalls();
                if (!canInstall) {
                    RxPermissions rxPermissions = new RxPermissions(MainActivity.this); // where this is an Activity instance
                    rxPermissions.request(Manifest.permission.REQUEST_INSTALL_PACKAGES) //权限名称,多个权限之间逗号分隔开
                            .subscribe(new Consumer<Boolean>() {
                                @Override
                                public void accept(Boolean granted) throws Exception {
                                    Log.e(TAG, "{accept}granted=" + granted);//执行顺序——1【多个权限的情况,只有所有的权限均允许的情况下granted==true】
                                    if (granted) { // 在android 6.0之前会默认返回true
                                        //安装APP
                                        AppUtils.installApk(MainActivity.this, apkFileSavePath);
                                    } else {
                                        Intent intent = new Intent(Settings.ACTION_MANAGE_UNKNOWN_APP_SOURCES, Uri.parse("package:" + getPackageName()));
                                        startActivityForResult(intent, 1000);
                                    }
                                }
                            }, new Consumer<Throwable>() {
                                @Override
                                public void accept(Throwable throwable) throws Exception {
                                    Log.e(TAG,"{accept}");//可能是授权异常的情况下的处理
                                }
                            }, new Action() {
                                @Override
                                public void run() throws Exception {
                                    Log.e(TAG,"{run}");//执行顺序——2
                                }
                            });
                } else {
                    //安装APP
                    AppUtils.installApk(MainActivity.this,apkFileSavePath);
                }
            } else {
                //安装APP
                AppUtils.installApk(MainActivity.this,apkFileSavePath);
            }
        }
    
        @Override
        protected void onActivityResult(int requestCode, int resultCode, Intent data) {
            super.onActivityResult(requestCode, resultCode, data);
            switch (requestCode) {
                case 1000:
                    checkOreo();
                    break;
            }
        }
    
    
        /**只有一个运行时权限申请的情况*/
        private void onePermission(){
            RxPermissions rxPermissions = new RxPermissions(MainActivity.this); // where this is an Activity instance
            rxPermissions.request(Manifest.permission.READ_EXTERNAL_STORAGE) //权限名称,多个权限之间逗号分隔开
                    .subscribe(new Consumer<Boolean>() {
                        @Override
                        public void accept(Boolean granted) throws Exception {
                            Log.e(TAG, "{accept}granted=" + granted);//执行顺序——1【多个权限的情况,只有所有的权限均允许的情况下granted==true】
                            if (granted) { // 在android 6.0之前会默认返回true
                                // 已经获取权限
                                Toast.makeText(MainActivity.this, "已经获取权限", Toast.LENGTH_SHORT).show();
                                downloadApkFile();
                            } else {
                                // 未获取权限
                                Toast.makeText(MainActivity.this, "您没有授权该权限,请在设置中打开授权", Toast.LENGTH_SHORT).show();
                            }
                        }
                    }, new Consumer<Throwable>() {
                        @Override
                        public void accept(Throwable throwable) throws Exception {
                            Log.e(TAG,"{accept}");//可能是授权异常的情况下的处理
                        }
                    }, new Action() {
                        @Override
                        public void run() throws Exception {
                            Log.e(TAG,"{run}");//执行顺序——2
                        }
                    });
        }
    
        /**模拟下载文件到手机本地目录下*/
        private void downloadApkFile(){
            String assetsFilePath = "wanandroid.apk";
            apkFileSavePath = AppDir.getInstance(MainActivity.this).DOWNLOAD + File.separator + "wanandroid.apk";
            DownloadUtil.copyOneFileFromAssetsToSD(MainActivity.this,assetsFilePath,apkFileSavePath);
        }
    
    }
    MainActivity.java

    混淆配置

    参考资料

    Android 7.0 行为变更 通过FileProvider在应用间共享文件吧

    项目demo下载地址

    https://github.com/haiyuKing/AppUtilsDemo

  • 相关阅读:
    SpringMVC
    Spring mvc 下Ajax获取JSON对象问题 406错误
    Docker国内镜像源
    获取redis cluster主从关系
    终端登录超时限制暂时解除
    vim全选,全部复制,全部删除
    [转]Redis集群搭建
    Jenkins持续集成01—Jenkins服务搭建和部署
    ELK重难点总结和整体优化配置
    ELK 经典用法—企业自定义日志收集切割和mysql模块
  • 原文地址:https://www.cnblogs.com/whycxb/p/9184096.html
Copyright © 2011-2022 走看看