在調試安卓程序的過程中,受不了每次看日誌查看網絡的響應和導出db的動作(甚至有時候都無法導出db),這裏安利一個facebook出品的神器 stetho,不過這個有些限制,在使用的時候一定的通過usb與調試的手機相連通的,也要使用chrome瀏覽器
1. stetho支持的功能
支持的功能主要是針對網絡和db的,看github項目上的趨勢,應該是在準備一些後續的功能(按照需求集成咯,我覺得網絡和db的最重要了),把官網的介紹摳了下來官網stetho介紹
1. 支持應用的網絡請求返回報文的查看
在chrome瀏覽器中輸入chrome://inspect
來進入。(第一次使用這個功能的時候要翻牆,翻牆,翻牆,重要的事情要說三遍,不然你點擊了inpect永遠是空白的)
2. 支持的db查看功能 和 支持的sql語句直接進行交互功能(增刪改查都是可以的)
2. 集成stetho
-
導入依賴
implementation ‘com.facebook.stetho:stetho:1.5.0’ -
根據網絡請求框架導入不同的依賴包
implementation ‘com.facebook.stetho:stetho-okhttp3:1.5.0’
or:
implementation ‘com.facebook.stetho:stetho-urlconnection:1.5.0’ -
在application中進行集成
public class MyApplication extends Application {
public void onCreate() {
super.onCreate();
Stetho.initializeWithDefaults(this);
}
}
- 如果是有網絡請求的,以okhttp舉例,創建okhttpClient的時候需要加入一個攔截器
new OkHttpClient.Builder() .addNetworkInterceptor(new StethoInterceptor()) .build()
3. 集成stetho的建議(乾貨)
-
建立一個單獨的productFlavor來集成功能,不要在正式的環境中集成這個東西。會使得應用變得更加龐大,也給應用留下漏洞
比如在build.gradle建立一個productflavorproductFlavors { { } }
在應用的的main目錄中建立一個productFlavor innerteset的目錄,然後把,通過清單合併操作中的替換application類的方式重新指定application.
-
關於網絡的請求中,有的應用的報文是有加解密的。這裏需要做一些額外的動作
修改默認的網絡請求攔截類StethoInterceptor.class
,新建的一個類把原來的類文件中東西拷貝出來進行調整
解密請求的報文,主要是修改內部類OkHttpInspectorRequest
的body()
,拿到原始報文的,請求體,完成解密動作後重新包裝生成一個請求體,給原來的代碼使用。下面有一個我在自己應用中使用的實例@Nullable public byte[] body() throws IOException { //我的測試應用的請求報文都是data:{}的格式,所以這裏這麼寫,各個應用要按照自己應用的需求改寫 FormBody copyedBody = (FormBody) (this.mRequest.body()); List<String> nameList = new ArrayList<>(); List<String> valusList = new ArrayList<>(); for (int i=0; i< copyedBody.size(); i++) { nameList.add(copyedBody.encodedName(i)); if ("data".equals(copyedBody.encodedName(i))) { valusList.add(new JsonFormatUtil().formart(這裏解密請求的報文)); } } FormBody copyedBody2 = new FormBody.Builder().add(nameList.get(0), valusList.get(0)).build(); FormBody body = copyedBody2; //下面這塊代碼不動,保持原樣,上面重新生成了requestBody而已 if (body == null) { return null; } else { OutputStream out = this.mRequestBodyHelper.createBodySink(this.firstHeaderValue("Content-Encoding")); BufferedSink bufferedSink = Okio.buffer(Okio.sink(out)); try { body.writeTo(bufferedSink); } finally { bufferedSink.close(); } return this.mRequestBodyHelper.getDisplayBody(); } }
解密返回報文,返回的報文,stetho是保存在文件中的然後進行的發送,需要修改默認的
ResponseHandler
抄襲原來的ReponseHanlder,主要修改的onEOF方式
//調整原來的類,增加一個readFile的方法 public void onEOF() { this.reportDataReceived(); try { readFile(this.mRequestId); } catch (IOException e) { Log.e(TAG, "readFile Exception onEOF: " + e); } this.mEventReporter.responseReadFinished(this.mRequestId); } //讀取默認的文件 public ResponseBodyData readFile(String requestId) throws IOException { ResponseBodyFileManager responseBodyFileManager = new ResponseBodyFileManager(CeshiApplication.getApplication()); ResponseBodyData responseBodyData = responseBodyFileManager.readFile(requestId); OutputStream outputStream = null; //這個對象是數據的對象,用於json轉換使用 SfReponseBodyData sfReponseBodyData = new Gson().fromJson(responseBodyData.data, SfReponseBodyData.class); sfReponseBodyData.data = 這裏就可以進行解密的動作,得到解密的字符串; try { outputStream = responseBodyFileManager.openResponseBodyFile(requestId, responseBodyData.base64Encoded); String data = new Gson().toJson(sfReponseBodyData); data = data.replace("\\", ""); data = new JsonFormatUtil().formart(data); outputStream.write(data.getBytes()); } catch (Exception e) { Log.e(TAG, "readFile Exception: " + e); } finally { if (null != outputStream) { outputStream.close(); } } LogUtils.getInstance().showLogD(TAG, "readFile" ,"new record"); return null; }
爲了在瀏覽器上好看,報文最後都需要進行格式化,比如我這裏是默認的json報文,就進行格式化後傳給瀏覽器
//網絡上隨便摳的一段格式代碼
public class JsonFormatUtil {
public String formart(String s) {
int level = 0;
//存放格式化的json字符串
StringBuilder jsonForMatStr = new StringBuilder();
for (int index = 0; index < s.length(); index++)//將字符串中的字符逐個按行輸出
{
//獲取s中的每個字符
char c = s.charAt(index);
//level大於0並且jsonForMatStr中的最後一個字符爲\n,jsonForMatStr加入\t
if (level > 0 && '\n' == jsonForMatStr.charAt(jsonForMatStr.length() - 1)) {
jsonForMatStr.append(getLevelStr(level));
}
//遇到"{"和"["要增加空格和換行,遇到"}"和"]"要減少空格,以對應,遇到","要換行
switch (c) {
case '{':
case '[':
jsonForMatStr.append(c + "\n");
level++;
break;
case ',':
jsonForMatStr.append(c + "\n");
break;
case '}':
case ']':
jsonForMatStr.append("\n");
level--;
jsonForMatStr.append(getLevelStr(level));
jsonForMatStr.append(c);
break;
default:
jsonForMatStr.append(c);
break;
}
}
return jsonForMatStr.toString();
}
private static String getLevelStr(int level) {
StringBuilder levelStr = new StringBuilder();
for (int levelI = 0; levelI < level; levelI++) {
levelStr.append("\t");
}
return levelStr.toString();
}
}