在android系统
中现在android studio3.+
版本上可通过Device File Explorer
下,选择data/data/
包名下的databases
查找对应的数据库并导出查看。
现我们可以采用 Android-Debug-DatabaseGitHub
上的此库对数据库、sharedprefrence
进行增删改查等操作。
Android Debug Database
可以做什么呢?
- 查看所有数据库
- 查看应用程序中使用的
shared preferences
所有数据 - 在给定数据库上运行任何sql查询以更新和删除数据
- 直接编辑数据库值。
- 直接编辑
shared preferences
。
....
1.接入方式build.gradle
debugImplementation 'com.amitshekhar.android:debug-db:1.0.4'
在2.x android studio
中
debugCompile 'com.amitshekhar.android:debug-db:1.0.4'
可能会存在can't find xxx
or failed to resolve xxx
可在project
下的 build.gradle
加入
jcenter()
maven {
url "https://jitpack.io"
}
Android 添加依赖failed to resolve xxxx库解决方案
2.真机调试
在Terminal
终端下运行adb forward tcp:8080 tcp:8080
,经测算真机或者模拟器均要启动命令开启端口才生效。以下分析估测为socket请求原因。
如果APP运行在手机上,此时保证手机和浏览器链接的是同一局域网下
的WiFi,可输入localhost:8080
或者加上代码Toast
提示手机此时的ip地址
、或者最直接Log.i
打印ip地址,点击即可到达浏览器。
public static void showDebugDBAddressLogToast(Context context) {
if (BuildConfig.DEBUG) {
try {
Class<?> debugDB = Class.forName("com.amitshekhar.DebugDB");
Method getAddressLog = debugDB.getMethod("getAddressLog");
Object value = getAddressLog.invoke(null);
Log.i("DebugDB_IPAddress", "Debug DB 下的IP地址"+value);
Toast.makeText(context, (String) value, Toast.LENGTH_LONG).show();
} catch (Exception ignore) {
}
}
}
DebugDB_IPAddress: Debug DB 下的IP地址Open http://172.20.188.2:8080 in your browser
3.模拟器调试:
在Terminal
终端下运行adb forward tcp:8080 tcp:8080
如果端口冲突可在gradle.build
下加入
buildTypes {
debug {
//更改此处端口
resValue("string", "PORT_NUMBER", "8088")
resValue("string", "DB_PASSWORD_PERSON", "a_password")
}
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}
adb forward tcp:8088 tcp:8088
在debug-db
库中的DebugDB.java
文件下开启了一个线程,并不断以socket
形式处理浏览器发过来的请求,判断socket发送过来的请求内容进行处理返回不通的结果。
public static void initialize(Context context) {
int portNumber;
try {
portNumber = Integer.valueOf(context.getString(R.string.PORT_NUMBER));
} catch (NumberFormatException ex) {
Log.e(TAG, "PORT_NUMBER should be integer", ex);
portNumber = DEFAULT_PORT;
Log.i(TAG, "Using Default port : " + DEFAULT_PORT);
}
clientServer = new ClientServer(context, portNumber);
clientServer.start();//开启线程
addressLog = NetworkUtils.getAddressLog(context, portNumber);
Log.d(TAG, addressLog);
}
public class ClientServer implements Runnable {
...
public ClientServer(Context context, int port) {
mRequestHandler = new RequestHandler(context);
mPort = port;
}
public void start() {
mIsRunning = true;
new Thread(this).start();
}
...
@Override
public void run() {
try {
mServerSocket = new ServerSocket(mPort);
while (mIsRunning) {
Socket socket = mServerSocket.accept();
mRequestHandler.handle(socket);
socket.close();
}
} catch (SocketException e) {
// The server was stopped; ignore.
} catch (IOException e) {
Log.e(TAG, "Web server error.", e);
} catch (Exception ignore) {
Log.e(TAG, "Exception.", ignore);
}
}
...
}
public class RequestHandler {
...
public RequestHandler(Context context) {
mContext = context;
mAssets = context.getResources().getAssets();
mGson = new GsonBuilder().serializeNulls().create();
}
public void handle(Socket socket) throws IOException {
BufferedReader reader = null;
PrintStream output = null;
try {
String route = null;
// Read HTTP headers and parse out the route.
reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
String line;
while (!TextUtils.isEmpty(line = reader.readLine())) {
if (line.startsWith("GET /")) {
int start = line.indexOf('/') + 1;
int end = line.indexOf(' ', start);
route = line.substring(start, end);
break;
}
}
// Output stream that we send the response to
output = new PrintStream(socket.getOutputStream());
if (route == null || route.isEmpty()) {
route = "index.html";
}
byte[] bytes;
if (route.startsWith("getDbList")) {
final String response = getDBListResponse();
bytes = response.getBytes();
} else if (route.startsWith("getAllDataFromTheTable")) {
final String response = getAllDataFromTheTableResponse(route);
bytes = response.getBytes();
} else if (route.startsWith("getTableList")) {
final String response = getTableListResponse(route);
bytes = response.getBytes();
} else if (route.startsWith("addTableData")) {
final String response = addTableDataAndGetResponse(route);
bytes = response.getBytes();
} else if (route.startsWith("updateTableData")) {
final String response = updateTableDataAndGetResponse(route);
bytes = response.getBytes();
} else if (route.startsWith("deleteTableData")) {
final String response = deleteTableDataAndGetResponse(route);
bytes = response.getBytes();
} else if (route.startsWith("query")) {
final String response = executeQueryAndGetResponse(route);
bytes = response.getBytes();
} else if (route.startsWith("downloadDb")) {
bytes = Utils.getDatabase(mSelectedDatabase, mDatabaseFiles);
} else {
bytes = Utils.loadContent(route, mAssets);
}
if (null == bytes) {
writeServerError(output);
return;
}
// Send out the content.
output.println("HTTP/1.0 200 OK");
output.println("Content-Type: " + Utils.detectMimeType(route));
if (route.startsWith("downloadDb")) {
output.println("Content-Disposition: attachment; filename=" + mSelectedDatabase);
} else {
output.println("Content-Length: " + bytes.length);
}
output.println();
output.write(bytes);
output.flush();
} finally {
try {
if (null != output) {
output.close();
}
if (null != reader) {
reader.close();
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
...
}
debug-db
将有交互性的html
发送给浏览器。
![](https://img.haomeiwen.com/i2981395/6fd677fd44f4fa49.png)
出现两个项目A、B都公用一个端口,A已开启端口,adb forward tcp:8080 tcp:8080
B也想用已开启的端口的服务,那么可以通过关闭A,再开启B。在DebugBD中
可以调用DebugDB.shutDown()
public class DebugDB {
...
public static void shutDown() {
if (clientServer != null) {
clientServer.stop();
clientServer = null;
}
}
...
![](https://img.haomeiwen.com/i2981395/9a6087003cbc00b8.png)
端口查看:netstat -aon|findstr "8080"
D:\androidstudio\work\WDSGQMSTrunk>netstat -aon|findstr "8080"
TCP 127.0.0.1:8080 0.0.0.0:0 LISTENING 8468
TCP 192.168.101.50:58779 223.167.104.149:8080 ESTABLISHED 11388
![](https://img.haomeiwen.com/i2981395/231b4d448029f5d0.png)
![](https://img.haomeiwen.com/i2981395/d4184a37b9d76f77.png)
记得操作后
重启APP
有时候不会生效。
netstat -ano | findstr "8080"(adb默认端口5037,现查找的为8080)
tasklist /fi "PID eq 8468"(找出来占端口的是谁)
taskkill /pid 8468 /f 除掉
adb默认的情况netstat -ano | findstr "5037"
可查看占用情况
netstat -ano
查看全部端口情况。
实在难得操作直接adb kill-server
再adb start -server
最终还是要重启App让其重新启动线程生效。
网友评论