学习目标:
学习目标:读取/data/data/下文件或者数据库,Android 11读写权限动态申请
前言
当开发一款新的app时需要另一款app数据相互依赖就需要去读数据但Android 11 上面变成了特殊权限需要
一、特殊权限是什么?
首先 Android 的权限大致分为三种:
1.普通权限:只需要在清单文件中注册即可
2.危险权限:需要在代码中动态申请,以弹系统 Dialog 的形式进行请求
3.特殊权限:需要在代码中动态申请,以跳系统 Activity 的形式进行请求
在 Android 6.0 之后就变成了危险权限,而到了 Android 11 上面变成了特殊权限,而最明显的区别是一个是通过 Dialog 展示给用户看,另外一个是通过 Activity 展现给用户看。
二、读取步骤
1.动静结合
静 代码如下(示例):
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" />
在AndroidManifest.xml文件中application节点中加上android:requestLegacyExternalStorage="true"属性
就可以了,如下:
<application
android:requestLegacyExternalStorage="true"
动 代码如下(示例):
private fun requestPermission() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
// 先判断有没有权限
if (Environment.isExternalStorageManager()) {
writeFile()
} else {
startActivityForResult(
Intent(Settings.ACTION_MANAGE_ALL_FILES_ACCESS_PERMISSION),
REQUEST_CODE
)
}
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
// 先判断有没有权限
if (ActivityCompat.checkSelfPermission(
this,
Manifest.permission.READ_EXTERNAL_STORAGE
) == PackageManager.PERMISSION_GRANTED &&
ContextCompat.checkSelfPermission(
this,
Manifest.permission.WRITE_EXTERNAL_STORAGE
) == PackageManager.PERMISSION_GRANTED
) {
writeFile()
} else {
ActivityCompat.requestPermissions(
this,
arrayOf(
Manifest.permission.READ_EXTERNAL_STORAGE,
Manifest.permission.WRITE_EXTERNAL_STORAGE
),
REQUEST_CODE
)
}
} else {
writeFile()
}
}
/**
* In this method, you can write the business logic related to reading and writing
*/
private fun writeFile() {
......
}
2.读入数据
数据权限已经申请了原本以为万事俱备只欠东风了可惜…读取的是另一个app的/data/data/这些显然不够,当然如果那么容易咱们的手机信息安全是个大问题呢 。当咱们是开发者只要咱们出发点是正义的为全人类制造福利的,正义无敌嘛哈哈。这个时候我想到了雷震子拿起了家伙事一顿操作猛似虎
1.下载模拟器
.
2.开启root权限
3.我们不能直接访问/data/data/下路径怎么搞呢?既然不能直接搞那我们间接的搞吧,打开命令框输入adb shell ,mkdir test 新建文件,cat /data/data/com.whatsapp/shared_prefs/keystore.xml > /sdcard/test/keystore.xml 复制 文件到指定文件对啊我们可以复制到可以访问的目录下载访问啊。可是咱们的这些都需要代码执行怎么搞呢…妈的坑真多哈哈其实这才是开始。咱们有root权限这玩意相当于你有上帝视角这他妈可不是开玩笑的,可以直接代码执行shell命令。shell的运行原理(shell是什么)Linux严格意义上是一个操作系统,我们称为核心,但我们一般的用户是不能直接使用核心的,而是通过外壳程序。也就是shell,对比Windows,图形界面就是外壳程序。shell的简单定义就是命令行解释器,功能是将使用者的命令翻译给核心处理,同时将核心处理的结果翻译给使用者。可以看出shell主要是对我们的指令进行解析,解析指令给Linux内核。反馈结果在通过内核运行出结果,通过shell解析给用户。
这是我们就可以理解为什么说外壳程序包裹着我们的操作系统,外壳程序仅仅对我们的指令进行解析,解析指令给Linux内核。反馈结果在通过内核运行出结果,通过shell解析给用户。
下面我们来接着了解shell。shell在解释命令的时候并不是自己亲自执行,而是派生子进程让子进程去完成这项工作,这样的好处是把风险交给别人,当指令的执行出现问题时不会影响到shell(影响到其他指令的执行)。shell不可以挂,shell 一旦挂就没有什么可以解释命令了。对我们而言shell为了保证自己风险最低,通过创建子进程进行命令行的解释工作。而shell自己只要去等就可以了。
可到底什么是shell呢?shell 是一个外壳程序统称,如Windows的图形界面(GUI),Linux下我们使用的bash就是具体的一种shell。 .
举个例子:shell是媒婆,那么bash就是王婆。shell是外壳程序的统称,bash 是具体的一种shell。
以上就是我们对shell初步的理解。
执行shell命令需要的工具类 代码如下(示例):
public final class ShellUtils {
private static final String LINE_SEP = System.getProperty("line.separator");
private ShellUtils() {
throw new UnsupportedOperationException("u can't instantiate me...");
}
/**
* Execute the command asynchronously.
*
* @param command The command.
* @param isRooted True to use root, false otherwise.
* @param consumer The consumer.
* @return the task
*/
public static Utils.Task<CommandResult> execCmdAsync(final String command,
final boolean isRooted,
final Utils.Consumer<CommandResult> consumer) {
return execCmdAsync(new String[]{command}, isRooted, true, consumer);
}
/**
* Execute the command asynchronously.
*
* @param commands The commands.
* @param isRooted True to use root, false otherwise.
* @param consumer The consumer.
* @return the task
*/
public static Utils.Task<CommandResult> execCmdAsync(final List<String> commands,
final boolean isRooted,
final Utils.Consumer<CommandResult> consumer) {
return execCmdAsync(commands == null ? null : commands.toArray(new String[]{}), isRooted, true, consumer);
}
/**
* Execute the command asynchronously.
*
* @param commands The commands.
* @param isRooted True to use root, false otherwise.
* @param consumer The consumer.
* @return the task
*/
public static Utils.Task<CommandResult> execCmdAsync(final String[] commands,
final boolean isRooted,
final Utils.Consumer<CommandResult> consumer) {
return execCmdAsync(commands, isRooted, true, consumer);
}
/**
* Execute the command asynchronously.
*
* @param command The command.
* @param isRooted True to use root, false otherwise.
* @param isNeedResultMsg True to return the message of result, false otherwise.
* @param consumer The consumer.
* @return the task
*/
public static Utils.Task<CommandResult> execCmdAsync(final String command,
final boolean isRooted,
final boolean isNeedResultMsg,
final Utils.Consumer<CommandResult> consumer) {
return execCmdAsync(new String[]{command}, isRooted, isNeedResultMsg, consumer);
}
/**
* Execute the command asynchronously.
*
* @param commands The commands.
* @param isRooted True to use root, false otherwise.
* @param isNeedResultMsg True to return the message of result, false otherwise.
* @param consumer The consumer.
* @return the task
*/
public static Utils.Task<CommandResult> execCmdAsync(final List<String> commands,
final boolean isRooted,
final boolean isNeedResultMsg,
final Utils.Consumer<CommandResult> consumer) {
return execCmdAsync(commands == null ? null : commands.toArray(new String[]{}),
isRooted,
isNeedResultMsg,
consumer);
}
/**
* Execute the command asynchronously.
*
* @param commands The commands.
* @param isRooted True to use root, false otherwise.
* @param isNeedResultMsg True to return the message of result, false otherwise.
* @param consumer The consumer.
* @return the task
*/
public static Utils.Task<CommandResult> execCmdAsync(final String[] commands,
final boolean isRooted,
final boolean isNeedResultMsg,
@NonNull final Utils.Consumer<CommandResult> consumer) {
return UtilsBridge.doAsync(new Utils.Task<CommandResult>(consumer) {
@Override
public CommandResult doInBackground() {
return execCmd(commands, isRooted, isNeedResultMsg);
}
});
}
/**
* Execute the command.
*
* @param command The command.
* @param isRooted True to use root, false otherwise.
* @return the single {@link CommandResult} instance
*/
public static CommandResult execCmd(final String command, final boolean isRooted) {
return execCmd(new String[]{command}, isRooted, true);
}
/**
* Execute the command.
*
* @param command The command.
* @param envp The environment variable settings.
* @param isRooted True to use root, false otherwise.
* @return the single {@link CommandResult} instance
*/
public static CommandResult execCmd(final String command, final List<String> envp, final boolean isRooted) {
return execCmd(new String[]{command},
envp == null ? null : envp.toArray(new String[]{}),
isRooted,
true);
}
/**
* Execute the command.
*
* @param commands The commands.
* @param isRooted True to use root, false otherwise.
* @return the single {@link CommandResult} instance
*/
public static CommandResult execCmd(final List<String> commands, final boolean isRooted) {
return execCmd(commands == null ? null : commands.toArray(new String[]{}), isRooted, true);
}
/**
* Execute the command.
*
* @param commands The commands.
* @param envp The environment variable settings.
* @param isRooted True to use root, false otherwise.
* @return the single {@link CommandResult} instance
*/
public static CommandResult execCmd(final List<String> commands,
final List<String> envp,
final boolean isRooted) {
return execCmd(commands == null ? null : commands.toArray(new String[]{}),
envp == null ? null : envp.toArray(new String[]{}),
isRooted,
true);
}
/**
* Execute the command.
*
* @param commands The commands.
* @param isRooted True to use root, false otherwise.
* @return the single {@link CommandResult} instance
*/
public static CommandResult execCmd(final String[] commands, final boolean isRooted) {
return execCmd(commands, isRooted, true);
}
/**
* Execute the command.
*
* @param command The command.
* @param isRooted True to use root, false otherwise.
* @param isNeedResultMsg True to return the message of result, false otherwise.
* @return the single {@link CommandResult} instance
*/
public static CommandResult execCmd(final String command,
final boolean isRooted,
final boolean isNeedResultMsg) {
return execCmd(new String[]{command}, isRooted, isNeedResultMsg);
}
/**
* Execute the command.
*
* @param command The command.
* @param envp The environment variable settings.
* @param isRooted True to use root, false otherwise.
* @param isNeedResultMsg True to return the message of result, false otherwise.
* @return the single {@link CommandResult} instance
*/
public static CommandResult execCmd(final String command,
final List<String> envp,
final boolean isRooted,
final boolean isNeedResultMsg) {
return execCmd(new String[]{command}, envp == null ? null : envp.toArray(new String[]{}),
isRooted,
isNeedResultMsg);
}
/**
* Execute the command.
*
* @param command The command.
* @param envp The environment variable settings array.
* @param isRooted True to use root, false otherwise.
* @param isNeedResultMsg True to return the message of result, false otherwise.
* @return the single {@link CommandResult} instance
*/
public static CommandResult execCmd(final String command,
final String[] envp,
final boolean isRooted,
final boolean isNeedResultMsg) {
return execCmd(new String[]{command}, envp, isRooted, isNeedResultMsg);
}
/**
* Execute the command.
*
* @param commands The commands.
* @param isRooted True to use root, false otherwise.
* @param isNeedResultMsg True to return the message of result, false otherwise.
* @return the single {@link CommandResult} instance
*/
public static CommandResult execCmd(final List<String> commands,
final boolean isRooted,
final boolean isNeedResultMsg) {
return execCmd(commands == null ? null : commands.toArray(new String[]{}),
isRooted,
isNeedResultMsg);
}
/**
* Execute the command.
*
* @param commands The commands.
* @param isRooted True to use root, false otherwise.
* @param isNeedResultMsg True to return the message of result, false otherwise.
* @return the single {@link CommandResult} instance
*/
public static CommandResult execCmd(final String[] commands,
final boolean isRooted,
final boolean isNeedResultMsg) {
return execCmd(commands, null, isRooted, isNeedResultMsg);
}
/**
* Execute the command.
*
* @param commands The commands.
* @param envp Array of strings, each element of which
* has environment variable settings in the format
* <i>name</i>=<i>value</i>, or
* <tt>null</tt> if the subprocess should inherit
* the environment of the current process.
* @param isRooted True to use root, false otherwise.
* @param isNeedResultMsg True to return the message of result, false otherwise.
* @return the single {@link CommandResult} instance
*/
public static CommandResult execCmd(final String[] commands,
final String[] envp,
final boolean isRooted,
final boolean isNeedResultMsg) {
int result = -1;
if (commands == null || commands.length == 0) {
return new CommandResult(result, "", "");
}
Process process = null;
BufferedReader successResult = null;
BufferedReader errorResult = null;
StringBuilder successMsg = null;
StringBuilder errorMsg = null;
DataOutputStream os = null;
try {
process = Runtime.getRuntime().exec(isRooted ? "su" : "sh", envp, null);
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 StringBuilder();
errorMsg = new StringBuilder();
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 (Exception e) {
e.printStackTrace();
} finally {
try {
if (os != null) {
os.close();
}
} catch (IOException e) {
e.printStackTrace();
}
try {
if (successResult != null) {
successResult.close();
}
} catch (IOException e) {
e.printStackTrace();
}
try {
if (errorResult != null) {
errorResult.close();
}
} catch (IOException e) {
e.printStackTrace();
}
if (process != null) {
process.destroy();
}
}
return new CommandResult(
result,
successMsg == null ? "" : successMsg.toString(),
errorMsg == null ? "" : errorMsg.toString()
);
}
/**
* The result of command.
*/
public static class CommandResult {
public int result;
public String successMsg;
public String errorMsg;
public CommandResult(final int result, final String successMsg, final String errorMsg) {
this.result = result;
this.successMsg = successMsg;
this.errorMsg = errorMsg;
}
@Override
public String toString() {
return "result: " + result + "\n" +
"successMsg: " + successMsg + "\n" +
"errorMsg: " + errorMsg;
}
}
}
/*
* 调用execCmd里面两个参数一个是shell命令,第二个是是否开启root返回的是return execCmd(new String[]{command}, isRooted, true)下面有调用实例successMsg
*/
val execCmd = ShellUtils.execCmd("写shell命令", true)
LogUtil.logGGQ("task", "输出结果-->${execCmd.successMsg}")
LogUtil.logGGQ("task", "输出结果-->${execCmd.errorMsg}")
LogUtil.logGGQ("task", "输出结果-->${execCmd.result}")
导入库
implementation 'com.blankj:utilcodex:1.30.6'
访问拷贝后的文件地址
val readFile2String = FileIOUtils.readFile2String("sdcard/android/axolotl.db")
LogUtil.logGGQ("task", "stringToBase64----->$readFile2String")
插入一个小知识点把String的转换成base64码
/**
* 把String的转换成base64码
*/
public static String stringToBase64(String ss) {
String encode="";
try{
byte[] bytes = ss.getBytes();
encode = Base64Util.encode(bytes);
// return encode;
}catch (Exception e){
LogUtil.logGGQ("task",e.getMessage());
}
return encode;
}
val stringToBase64 = Base64Object.stringToBase64(readFile2String)
LogUtil.logGGQ("task", "stringToBase64----->$stringToBase64")
放文件到这就结束了
数据库文件查看
复制和上面一样代码执行shell
/*
*数据库打开文件路径
*/
val database: SQLiteDatabase = SQLiteDatabase.openOrCreateDatabase(
"sdcard/android/axolotl.db", null
)