AppUtils【獲取手機的信息和應用版本號、安裝apk】

版權聲明:本文爲HaiyuKing原創文章,轉載請註明出處!html

前言

一個獲取設備的系統版本號、設備的型號、應用版本號code值、應用版本號name值、包名、是否更新、安裝apk的工具類。java

其實這個工具類的主要功能是安裝apk方法,因此須要搭配《Android6.0運行時權限(基於RxPermission開源庫)》、《AppDir【建立緩存目錄】》【這個是用來存放下載的apk文件的,能夠不用】。react

下載apk的過程沒有使用網路請求,而是經過模擬的方式:其實就是從assets目錄複製apk文件到手機目錄中。android

效果圖

 

代碼分析

須要注意的代碼包括如下部分:git

一、下載apk以前須要先申請運行時權限(READ_EXTERNAL_STORAGE),我是在項目啓動的時候申請的,不是在事件觸發的時候申請的;github

二、適配7.0FileProvider緩存

三、安裝前先適配8.0請求未知來源權限服務器

使用步驟

1、項目組織結構圖

注意事項:app

一、  導入類文件後須要change包名以及從新import R文件路徑ide

二、  Values目錄下的文件(strings.xml、dimens.xml、colors.xml等),若是項目中存在,則複製裏面的內容,不要整個覆蓋

2、導入步驟

將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【建立緩存目錄】》導入相關文件。

3、使用方法

常規方法調用【獲取設備型號、版本號、應用版本號、包名等】

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 +
                        "\n設備的型號:" + DeviceName +
                        "\n應用版本號code值:" + VersionCode +
                        "\n應用版本號name值:" + VersionName +
                        "\n包名:" + PackageName +
                        "\n是否更新(服務器版本號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 +
                        "\n設備的型號:" + DeviceName +
                        "\n應用版本號code值:" + VersionCode +
                        "\n應用版本號name值:" + VersionName +
                        "\n包名:" + PackageName +
                        "\n是否更新(服務器版本號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

相關文章
相關標籤/搜索