有的时候写完关于sqlite的操作逻辑,需要进行验证。最笨的就是处理完之后通过代码读取内容打印到logcat中查看。但是,可以使用adb把db文件读取到本地,然后使用sqlite对应的管理工具打开查看不更方便吗?下面就会介绍如何实现这种操作。
注意:下面所有操作假设设备已经具有root权限,否则没有权限读取这些数据
存储位置
一个应用的db文件存储在/data/data/your package name/databases/
下面。
adb介绍
Android Debug Bridge是Google提供的调试工具。
上图是adb的基本结构。adb存在三种成员:
- client:这个是在开发的机器上面,可以具有多个client,用于请求server操作设备。
- server:这个也是在开发的机器上面,用于管理client和各个设备上的daemon之间的数据交流,只有一个实例。当一个client启动的时候,如果不存在server,那么则会启动server,其他则不处理。
- daemon:这个在设备(包括实际的模拟器)上面,是设备上后台运行的进程。
从上面的图也可以看出来,adb是client-server模式的。
只有在设备打开开发者选项中的调试模式的时候adb才会有作用
常见命令
adb [-d|-e|-s [serial number]] shell [command]
这条命令用于打开特定设备的shell。其中-d表示连接实体设备,-e表示模拟器,-s表示连接特定的设备,使用后面的serial number来确定设备。如果只有一台连接设备的情况下不需要指明设备编号,adb会自动指定。如果是多台设备必须指明serial number最后的command是要直接执行的命令,如果没有则直接进入shell。
adb pull <remote> <local>
这条命令用于把设备上的文件复制到本地。
adb push <local> <remote>
这条命令用于把本地的文件复制到设备上面。
adb devices
这条命令用于查看当前连接设备的情况,包括设备的serial number以及状态(offline和online)。
adb install <local>
这条命令用于在设备上安装apk文件。
因为进入shell之后就是操作Android,由于Android是基于Linux内核,因此需要使用几个常用的Linux命令。
ls
cd
用于切换目录,其中
cd..
用于退到上一级目录。cat
复制sqlite文件到本地
具体命令如下:
adb -d shell 'run-as your_package_name cat /data/data/your_package_name/databases/your_db_file_name > /sdcard/your_db_file_name'
adb pull /sdcard/your_db_file_name location_of_file_in_your_machine
Starting from API level 8 (Android 2.2),if you build the application as debuggable,you can use the shell run-as command to run a command or executable as a specific user/application or just switch to the UID of your application so you can access its data directory.
从API 8开始需要使用
run-as
命令加上特定的包名或者应用的UID之后,才能获取到data目录下的数据。这个就是上面的命令中使用run-as
命令的原因。使用pull命令直接复制db文件会被拒绝,因此需要先用cat命令把对应的db文件复制到sdcard上面,然后再使用pull命令把文件复制到本地。
具体说明可以参阅:Debugging sqlite database on the device
打开cmd,切换到your_sdk_directory/platform-tools
下面,然后执行上面两个命令就可以把db文件复制到本地特定的位置了。
脚本实现复制
上面的命令已经很简单了,但是如果以后想使用的话,就需要自己一点一点去改命令中的参数,但是如果可以使用代码实现输入对应的参数然后自动执行就好了,下面的代码就是实现了这个功能。
import java.util.Scanner;
import java.io.FileWriter;
import java.io.BufferedWriter;
import java.io.File;
/** * @author jy.wang */
public class AdbPullDatabase{
public static void main(String args[]){
Scanner sin = new Scanner(System.in);
System.out.println("Please input adb directory:");
final String adbDirectory =sin.nextLine().trim();
System.out.println();
System.out.print("Please input package name:");
final String packageName = sin.nextLine().trim().split("\\s+")[0];
System.out.println();
System.out.print("Please input database name:");
final String dbName = sin.nextLine().trim().split("\\s+")[0];
System.out.println();
System.out.print("Please input database location:");
final String dbLocation = sin.nextLine().split("\\s+")[0];
System.out.println();
sin.close();
try{
final String changeDirectory = "cd /d "+adbDirectory;
final String saveToSdCardCommand = "adb -d shell 'run-as "+packageName+" cat /data/data/"+packageName+"/databases/"+dbName+" > /sdcard/"+dbName+"'";
final String pullDBCommand = "adb pull /sdcard/"+dbName+" "+dbLocation;
File file = new File("command.bat");
BufferedWriter writer = new BufferedWriter(new FileWriter(file));
writer.write(changeDirectory,0,changeDirectory.length());
writer.newLine();
writer.write(saveToSdCardCommand,saveToSdCardCommand.length());
writer.newLine();
writer.write(pullDBCommand,pullDBCommand.length());
writer.close();
Runtime.getRuntime().exec("cmd /c start "+file.getAbsolutePath());
}catch(Exception e){
e.printStackTrace();
}
}
}
其中使用了bat批处理文件实现java调用多条cmd命令的技巧,具体可以参阅Java中调用多条cmd命令