设备已 root,不然无法访问 data/data 目录
问题现象:
HIE_Find(com.estrongs.android.pop) APP 可直接打开 usb 存储设备,但每次插拔后 usb 设备节点名称发生改变,再次打开 app 总会记住上一次打开路径
导致无法正常返回其它目录。通过分析,上次路径存储在了 SharedPreferences 中的 last_content_chooser_path
其实还有一种方法,但是只能用 adb 指令跳转
shell am start -n com.estrongs.android.pop/com.estrongs.android.pop.app.ESContentChooserActivity -d “file:///storage/emulated/0/DCIM/”
就可以打开指定路径选择文件,但在高版本上,由于文件权限机制问题,必须要用 FileProvider 来构造 uri,但这样 HIE_Find 不兼容,所以无法成功跳转
所以可行办法就是直接修改 last_content_chooser_path
注意: 修改完 SharedPreferences 后,对应 app 需要重新启动一次才会读取修改后的值
public void setLastContentChooserPath() {
// /data/data/com.estrongs.android.pop/shared_prefs/com.estrongs.android.pop_preferences.xml
// /storage/emulated/0/DCIM/
String cmd1 = "chmod 777 /data/data/com.estrongs.android.pop/";
String cmd2 = "chmod 777 /data/data/com.estrongs.android.pop/shared_prefs/";
String cmd3 = "chmod 777 /data/data/com.estrongs.android.pop/shared_prefs/com.estrongs.android.pop_preferences.xml";
String[] cmds = {cmd1, cmd2, cmd3};
ShellUtils.CommandResult result = ShellUtils.execCmd(cmds, true);
Log.i(TAG, "result======"+result.successMsg);
try {
File preffile = new File("/data/data/com.estrongs.android.pop/shared_prefs/com.estrongs.android.pop_preferences.xml");
Class prefimplclass = Class.forName("android.app.SharedPreferencesImpl");
Constructor prefimplconstructor = prefimplclass.getDeclaredConstructor(File.class, int.class);
prefimplconstructor.setAccessible(true);
SharedPreferences prefimpl = (SharedPreferences) prefimplconstructor.newInstance(preffile, Context.MODE_WORLD_READABLE
| Context.MODE_WORLD_WRITEABLE);
String chooserPath = prefimpl.getString("last_content_chooser_path", "");
Log.i(TAG, "chooserPath======"+chooserPath);
SharedPreferences.Editor editor = (SharedPreferences.Editor) prefimplclass.getMethod("edit").invoke(prefimpl);
editor.putString("last_content_chooser_path", "/storage/emulated/0/DCIM/");
editor.commit();
Log.i(TAG, "set last_content_chooser_path======");
} catch (Exception e) {
e.printStackTrace();
}
}
ShellUtils.java
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.
*
* @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 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 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 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) {
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");
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;
}
}
}