android 命令與代碼進行安裝應用

1.安裝應用

//下載應用到自己的手機上,本例將安裝包放在asset上,直接讀取寫入手機的存儲卡路徑中

清單文件聲明權限

//android8.0需要install_packages權限,清單文件註冊即可,無需動態申請權限

 <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"></uses-permission>
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"></uses-permission>
    <uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES"></uses-permission>


android 7.0以上使用FileProvider

清單文件中聲明

<provider
            android:name="cn.demo.android8demo.traction.FileProviderUtil"
            android:authorities="${applicationId}.provider"
            android:exported="false"
            android:grantUriPermissions="true">
            <meta-data
                android:name="android.support.FILE_PROVIDER_PATHS"
                android:resource="@xml/provide_paths"></meta-data>
        </provider>

provide_paths.xml文件 (寫出所需的目錄即可)

<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
    <!--內部存儲空間應用私有目錄下cache/目錄,等同於Context.getCacheDir()-->
    <cache-path
        name="cache_path"
        path="."></cache-path>
    <!--外部存儲空間根目錄,等同於Environment.getExternalStorageDirectory()-->
    <external-path
        name="external_path"
        path="."></external-path>
    <!--外面存儲空間應用私有目錄下files/目錄,等同於Context.getExternalFilesDir(null)-->
    <external-files-path
        name="exteranl_files_path"
        path="."></external-files-path>
    <!--外部存儲空間應用私有目錄下cache/目錄,等同於Context.getExternalCacheDir()-->
    <external-cache-path
        name="external_cache_path"
        path="."></external-cache-path>
    <!--內部存儲空間私有目錄files目錄等同於Context.getFilesDir()-->
    <files-path
        name="files_path"
        path="."></files-path>
 
</paths>

1) . 適配android6.0以上

//android8.0以後,權限申請的話,一個權限組的,只要同意一個權限就會默認整個權限組同意,即android8.0以下兩個權限只有同意一個即可。

 //該執行需要兩個權限
  

String[] permissions = new String[]{
                        Manifest.permission.READ_EXTERNAL_STORAGE,
                        Manifest.permission.WRITE_EXTERNAL_STORAGE
                };
                //判斷當前權限 低版本直接通過,高版本判斷權限
                if (Build.VERSION.SDK_INT > Build.VERSION_CODES.M) {
                    if (ActivityCompat.checkSelfPermission(this, permissions[0]) == PackageManager.PERMISSION_GRANTED &&
                            ActivityCompat.checkSelfPermission(this, permissions[1]) == PackageManager.PERMISSION_GRANTED) {
                        installApk();
                    } else {
                        ActivityCompat.requestPermissions(this, permissions, 11);
                    }
                } else {
                    installApk();
                }


處理權限申請

    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        switch (requestCode) {
            case 11:
                if (grantResults[0] == PackageManager.PERMISSION_GRANTED && grantResults[1] == PackageManager.PERMISSION_GRANTED) {
                    installApk();
                }
                break;
        }
    }


2)、準備安裝的apk文件

private void installApk(){ 
File cacheDir = getExternalCacheDir();
        String CACHE_PATH;
        if (cacheDir != null) {
            CACHE_PATH = cacheDir.getAbsolutePath();
        } else {
            CACHE_PATH = Environment.getExternalStorageDirectory().getAbsolutePath();
        }
        String path = CACHE_PATH + System.getProperty("file.separator") + "test.apk";
        final File apkFile = new File(path);//創建存儲路徑
        if (!apkFile.exists()) {
            Executor executor = Executors.newSingleThreadExecutor();
            executor.execute(new Runnable() {
                @Override
                public void run() {
                    try {//將asset目錄下的文件讀取出來
                        InputStream inputStream = getAssets().open("test.apk");
                        OutputStream os = null;
                        os = new BufferedOutputStream(new FileOutputStream(apkFile, false));
                        byte data[] = new byte[8192];
                        int len;
                        while ((len = inputStream.read(data, 0, 8192)) != -1) {
                            os.write(data, 0, len);
                        }
                        if (inputStream != null)
                            inputStream.close();
                        if (os != null)
                            os.close();
 
                    } catch (IOException e) {
                        e.printStackTrace();
                    }//讀取文件之後執行安裝
                    install(apkFile);
                }
            });
        } else {//有文件的時候直接執行安裝
            install(apkFile);
        }
}

3)、開始安裝文件 android8.0添加一個允許安裝第三方應用,需要用戶手動授權處理

可以用canRequestPackageInstalls來判斷用戶是否授權,未授權,跳轉到相應的頁面進行操作。

 

 /**
     * 跳轉到安裝頁面
     *
     * @param apkFile
     */
    private void install(File apkFile) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            boolean b = getPackageManager().canRequestPackageInstalls();
            if (b) {
                startInstall(apkFile);
            } else {//跳轉到應用授權安裝第三方應用權限
                Intent intent = new Intent(Settings.ACTION_MANAGE_UNKNOWN_APP_SOURCES);
                startActivity(intent);
            }
        } else {
            startInstall(apkFile);
        }
    }


4)、跳轉到應用的安裝頁面,將文件帶到安裝頁面進行安裝

android8.0需要添加授權fileprovider授權權限,不能使用newtask標誌位

 

 private void startInstall(File apkFile) {
        Intent intent1 = new Intent(Intent.ACTION_VIEW);
        Uri data;
        String type = "application/vnd.android.package-archive";
        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N) {
            data = Uri.fromFile(apkFile);
            intent1.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        } else {
            intent1.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
            String authority = getPackageName() + ".provider";
            data = FileProvider.getUriForFile(this, authority, apkFile);
            intent1.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
        }
        intent1.setDataAndType(data, type);
        startActivity(intent1);
    }


2.靜默安裝應用

獲取文件跟上面的一樣

判斷當前設備是否有root權限

   

private boolean isRoot(){
        String su = "su";
        //手機本來已經有root權限(/system/bin/su已經存在,adb shell裏面執行su就可以切換root權限下)
        String[] locations = {"/system/bin/", "/system/xbin/", "/sbin/", "/system/sd/xbin/",
                "/system/bin/failsafe/", "/data/local/xbin/", "/data/local/bin/", "/data/local/"};
        for (String location : locations) {
            if (new File(location + su).exists()) {
                return true;
            }
        }
        return false;
    }
  private boolean installSilent(File apkFile) {
        boolean isDeviceRoot = isRoot();
        String filePath = '"' + apkFile.getAbsolutePath() + '"';
        String command = "LD_LIBRARY_PATH=/vendor/lib*:/system/lib* pm install " + filePath;
        CommandResult commandResult = execCmd(new String[]{command}, isDeviceRoot, true);
        if (commandResult.successMsg != null && commandResult.successMsg.toLowerCase().contains("success")) {
            return true;//安裝成功
        } else {
            return false;//安裝失敗
        }
    }


命令行執行

 

private static final String LINE_SEP = System.getProperty("line.separator");
 
    private CommandResult execCmd(String[] commands, boolean isRoot, boolean isNeedResultMsg) {
        int result = -1;
        if (commands == null || commands.length == 0) {
            return new CommandResult(result, null, null);
        }
        Process process = null;
        BufferedReader successResult = null;
        BufferedReader errorResult = null;
        StringBuffer successMsg = null;
        StringBuffer errorMsg = null;
 
        DataOutputStream os = null;
        try {
            //root過的手機上面獲得root權限
            process = Runtime.getRuntime().exec(isRoot ? "su" : "sh");
            os = new DataOutputStream(process.getOutputStream());
            for (String command : commands) {
                if (command == null)
                    continue;
                os.write(command.getBytes());
                os.writeBytes(LINE_SEP);
                os.flush();
            }
            os.writeBytes("exit" + LINE_SEP);
            os.flush();
            result = process.waitFor();
            if (isNeedResultMsg) {
                successMsg = new StringBuffer();
                errorMsg = new StringBuffer();
                successResult = new BufferedReader(new InputStreamReader(process.getInputStream(),
                        "UTF-8"));
                errorResult = new BufferedReader(new InputStreamReader(process.getErrorStream(),
                        "UTF-8"));
                String line;
                if ((line = successResult.readLine()) != null) {
                    successMsg.append(line);
                    while ((line = successResult.readLine()) != null) {
                        successMsg.append(LINE_SEP).append(line);
                    }
                }
                if ((line = errorResult.readLine()) != null) {
                    errorMsg.append(line);
                    while ((line = errorResult.readLine()) != null) {
                        errorMsg.append(LINE_SEP).append(line);
                    }
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            try {
                if (os != null)
                    os.close();
                if (successResult != null)
                    successResult.close();
                if (errorResult != null)
                    errorResult.close();
                if (process != null)
                    process.destroy();
            } catch (IOException e) {
                e.printStackTrace();
            }
 
        }
        return new CommandResult(result, successMsg == null ? null : successMsg.toString(),
                errorMsg == null ? null : errorMsg.toString());
    }


模型

public class CommandResult {
 
    public int result;
    public String successMsg;
    public String errorMsg;
 
    public CommandResult(int result, String successMsg, String errorMsg) {
        this.result = result;
        this.successMsg = successMsg;
        this.errorMsg = errorMsg;
    }
}


3.卸載應用

Intent intent=new Intent(Intent.ACTION_DELETE);
intent.setData(Uri.parse("package:包名"));
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);


4.靜默卸載應用 

/**
     * 卸載應用成功&失敗
     * @param packageName
     * @param isKeepData
     * @return
     */
    private boolean uninstallSilent(String packageName,boolean isKeepData){
        boolean isRoot=isRoot();
        String command="LD_LIBRARY_PATH=/vendor/lib*:/system/lib* pm uninstall "+(isKeepData?"-k":"")+packageName;
        CommandResult commandResult=execCmd(new String[]{command},isRoot,true);
        if (commandResult.successMsg!=null
                && commandResult.successMsg.toLowerCase().contains("success")){
            return true;
        }else {
            return false;
        }
    }

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章