android调试stetho的那点事

Posted xjz729827161

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了android调试stetho的那点事相关的知识,希望对你有一定的参考价值。

在调试安卓程序的过程中,受不了每次看日志查看网络的响应和导出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的建议(干货)

  1. 建立一个单独的productFlavor来集成功能,不要在正式的环境中集成这个东西。会使得应用变得更加庞大,也给应用留下漏洞
    比如在build.gradle建立一个productflavor

     productFlavors 
         
           
        
    
    

    在应用的的main目录中建立一个productFlavor innerteset的目录,然后把,通过清单合并操作中的替换application类的方式重新指定application.

  2. 关于网络的请求中,有的应用的报文是有加解密的。这里需要做一些额外的动作
    修改默认的网络请求拦截类 StethoInterceptor.class,新建的一个类把原来的类文件中东西拷贝出来进行调整
    解密请求的报文,主要是修改内部类OkHttpInspectorRequestbody(),拿到原始报文的,请求体,完成解密动作后重新包装生成一个请求体,给原来的代码使用。下面有一个我在自己应用中使用的实例

      @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();
    

以上是关于android调试stetho的那点事的主要内容,如果未能解决你的问题,请参考以下文章

几种适配器&观察者&ListView之间的那点事

python与中文的那点事

this的那点事

重载delete时的那点事

TODO:字节的那点事Go篇

TODO:字节的那点事Go篇