android Debugging stetho's Things

Keywords: Mobile network JSON github OkHttp

In the process of debugging Android program, I can't stand every time I look at the log to check the response of the network and export DB (even sometimes I can't export db). Here is a facebook artifact stetho, but this is a limitation. When I use it, I must connect with the debugged mobile phone through usb, and also use chrome browser.

1. Functions supported by stetho

The support functions are mainly for network and db. See github project The trend should be to prepare some follow-up functions (integration according to requirements, I think the most important network and db), to cut down the introduction of the official website.stetho Introduction on Official Website

1. View of Application-Supported network request return message

Enter chrome://inspect in the chrome browser. (The first time you use this function, you have to turn over the wall, turn over the wall, turn over the wall, say important things three times, otherwise you click on the inpect will always be blank)

2. Supported db viewing functions and supported sql statements directly interact with each other (add, delete and modify checks are all possible)

2. Integrated stetho

  • Import dependency
    implementation 'com.facebook.stetho:stetho:1.5.0'

  • Importing different dependency packages according to the network request framework
    implementation 'com.facebook.stetho:stetho-okhttp3:1.5.0'
    or:
    implementation 'com.facebook.stetho:stetho-urlconnection:1.5.0'

  • Integration in application

public class MyApplication extends Application {
  public void onCreate() {
    super.onCreate();
    Stetho.initializeWithDefaults(this);
  }
}
  • If there is a network request, take okhttp as an example. When creating okhttpClient, you need to add an interceptor.
    new OkHttpClient.Builder()
      .addNetworkInterceptor(new StethoInterceptor())
      .build()
    

3. Integrating stetho's Suggestions (Dry Goods)

  1. Create a separate product Flavor to integrate functionality, not in a formal environment. It will make the application bigger and leave loopholes for the application.
    For example, build a product flavor in build.gradle

     productFlavors {
         {
           
        }
    }
    

    Create a product Flavor innerteset directory in the main directory of the application, and then re-specify the application by replacing the application class in the list merge operation.

  2. In network requests, some application messages are encrypted and decrypted. There are some extra actions that need to be done here.
    Modify the default network request interception class StethoInterceptor.class, and create a new class that copies everything from the original class file for adjustment.
    Decrypting the request message is mainly to modify the body() of the internal class OkHttp InspectorRequest, get the original message, request body, complete the decryption action, repackage and generate a request body, to use the original code. Here's an example I use in my own application

      @Nullable
        public byte[] body() throws IOException {
    	//The request message of my test application is in data:{} format, so as I write here, each application should be rewritten according to its own application requirements.
            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(Here decrypt the requested message));
                }
            }
    
            FormBody copyedBody2 = new FormBody.Builder().add(nameList.get(0), valusList.get(0)).build();
            FormBody body = copyedBody2;
    		//The following code stays the same and reproduces the request Body on it.
            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();
            }
    
        }
    

    Decrypted return message, returned message, stetho is saved in the file and then sent, need to modify the default ReponseHandler
    Copy the original Reponse Hanlder, the main modification of the onEOF mode

       //Adjust the original class and add a readFile method
        public void onEOF() {
        this.reportDataReceived();
        try {
            readFile(this.mRequestId);
        } catch (IOException e) {
            Log.e(TAG, "readFile Exception onEOF:  " + e);
        }
        this.mEventReporter.responseReadFinished(this.mRequestId);
    }
    
    //Read the default file
    public ResponseBodyData readFile(String requestId) throws IOException {
        ResponseBodyFileManager responseBodyFileManager = new ResponseBodyFileManager(CeshiApplication.getApplication());
        ResponseBodyData responseBodyData = responseBodyFileManager.readFile(requestId);
        OutputStream outputStream = null;
    	//This object is an object of data for json transformation
        SfReponseBodyData sfReponseBodyData = new Gson().fromJson(responseBodyData.data, SfReponseBodyData.class);
        sfReponseBodyData.data = Here you can decrypt the action to get the decrypted string;
        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;
    }
    
    

    In order to look good on the browser, messages need to be formatted at last. For example, I am the default json message here, and then format it and pass it to the browser.

//A Format Code on the Network
public class JsonFormatUtil {

    public String formart(String s) {
        int level = 0;
        //Store formatted json strings
        StringBuilder jsonForMatStr = new StringBuilder();
        for (int index = 0; index < s.length(); index++)//Line-by-line output of characters in a string
        {
            //Get each character in s
            char c = s.charAt(index);

            //level is greater than 0 and the last character in JSON ForMatStr is n. JSON ForMatStr adds t
            if (level > 0 && '\n' == jsonForMatStr.charAt(jsonForMatStr.length() - 1)) {
                jsonForMatStr.append(getLevelStr(level));
            }
            //When encountering "{" and "[", add spaces and line breaks, when encountering "}" and "]", reduce spaces to correspond, when encountering "," line breaks.
            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();
    }
}

Posted by Quest on Sun, 27 Jan 2019 11:30:16 -0800