Developers want to check the network access and data storage of android APP during development. Debugging is too troublesome and logging is also annoying. Is there a better way? Facebook is spreading the Gospel to developers, bringing benefits, and putting it on the small table at afternoon tea

Engaged in the development of mobile Android APP, in addition to code logic is dealing with data. Data input and output, shuttled back and forth between network interfaces, are stored in memory and cannot be seen directly in the code editor as written code. So if you want to see if the data is true or false, for now, there are three ways to do it. This article begins by telling you the fourth way.

The status quo, and their respective problems

Traditionally, there are two ways for developers to view the data processed during an APP run. Here’s a brief description of the processing and the pros and cons of each.

  • Breakpoints debug running APP. You can debug an APP directly with the debugger, but if the APP is too large and takes too long to load initially, the best way to debug is to run the APP on the device (phone or emulator) and attach the debugger to the debugger by attaching it to the debugger. This will be faster than just debugging the APP in the first place. The debugger attached to the APP process will automatically shut down the application and then view the values of various variables in the current context as well as the data in memory. You can also modify the data. However, if you want to see if some data is actually written to the stored file, you probably need to add extra reading code to check, and it’s still a little inconvenient to hang the debugger on your APP every time to see the data. If you want to diagnose and analyze network access speed and data traffic, data storage space and total data volume, debugging alone is not a powerful tool. In addition, if the breakpoint is somewhere in the UI code and the data is viewed in the breakpoint state for a long time, ANR exceptions will occur in the APP.

  • Add print log. Buried point of the operation of similar products and services to access/operation log, we can also in the big book client APP corresponding position here and like to swim and three hundred without her beautiful sentence, let APP process through an old thing called the console (the console is a computer world of the old driver, what the wind waves have not seen) tells us what happened, How it happened, and what happened with the results. Things like network access speed and data traffic that breakpoints are not easy to achieve can also be called by logging. So it seems like logging is a perfect way to do it. But, do you feel like this is super troublesome? First of all, your code volume suddenly becomes large, the code structure becomes ugly, the code environmental health becomes poor, I dare not eat the sauerkraut on cuihua. Trust me, the Log Sea will make your tired eyes feel like a boat in a storm, turning over without batting an eye. Logging is an intrusive means of debugging. What is intrusive? Even if it must be by your old people personally buried in the heart of the code, until the end of time, APP off the shelf, it will not turn into a bit of mud more protection flowers. And for debugging, the mood of the log is less than lower, cookie-cutter flying is like chewing wax. Those who have seen android logs know that the past is not a misty cloud, and those who shout and shout in the wechat group every day come to see what is called brush screen. Poor Android developers are flooded with logs every day.

  • Use third-party tools. For networks, this is basically about setting up proxies, the most common being Charles (paid, java-based, cross-platform); Fiddler (free & paid, based. Net, currently supports running on Mac and Linux via Mono); Mitmproxy (free & open source, Python based, cross-platform); There are more complicated methods, such as Http/Https proxy +Wireshark/tcpdump. These tools are only good for network monitoring, not for non-network data. For the data stored on the mobile phone, you can log in to the mobile phone through ADB and view the internal data of the APP after obtaining root permission. You can also view and modify the data by using some apps with graphical interface installed on the mobile terminal, such as SQLEditor, which also need to obtain root permission.

Well, then, Facebook brought us poor kids a blessing and a blessing, so give it a try

Here comes the stethoscope

Stetho (Stetho) is an Android APP framework for network diagnosis and data monitoring developed by Facebook. It is now open source, and developers can access the SDK provided by Stetho framework into the APP, so that it can be installed on the developer machine (PC/MAC, Google Chrome Developer tools installed on Windows/OS X/Linux (used through the Chrome browser) to view, diagnose, and analyze web requests and responses as well as data content that occur in your APP, just like you would debug a web site with Chrome. Of course, almost any tool comes with an old driver console, and Stetho is no exception. It offers a tool called Dumpapp that tells you more about the inner world of your APP.

Access is simple

There are always 1234 steps to simple access, so here are a few simple words.

Gradle configuration

Instead of using MVN and low to download and copy libraries, you can configure gradle directly

/ / Gradle dependency on Stetho dependencies {the compile 'com. Facebook. Stetho: Stetho: 1.3.1'}Copy the code

If you are using the Okhttp 3.x networking stack, please integrate the following networking libraries

Dependencies {the compile 'com. Facebook. Stetho: stetho - okhttp3:1.3.1'}Copy the code

Okhttp 2.2 x +

Dependencies {the compile 'com. Facebook. Stetho: stetho - okhttp: 1.3.1'}Copy the code

If HttpURLConnection is used

Dependencies {the compile 'com. Facebook. Stetho: stetho - urlconnection: 1.3.1'}Copy the code

Please note to the white Rabbit and the Wolf:

  • If you are using Apache HttpClient, sorry, you are out, please upgrade the network stack, of course, you can also learn to understand Stetho’s play after writing a set of network monitoring to Apache HttpClient.

  • If you use a network stack that is not listed above, or if you write network operations in C/C ++, or if you use a protocol other than HTTP/HTTPS, then this part of the network diagnosis and monitoring approach is probably difficult to use. If you want to use it, write it yourself.

Initialize the

There is very little code to write, and almost all applications have the same code, starting with initialization in the Application class

public class MyApplication extends Application { public void onCreate() { super.onCreate(); Stetho.initializeWithDefaults(this); }}Copy the code

This initialization turns on most auscultation modules, except for some additional hook modules such as network monitoring

Network in the diagnosis of

If you are using the network stack OkHttp and the version range is 2.2.x+ to 3.x, all you need to do to open the network diagnostics module is to call the following code at the appropriate place in your application

OkHttp 2.2 x +

OkHttpClient client = new OkHttpClient();
client.networkInterceptors().add(new StethoInterceptor());Copy the code

OkHttp 3.x

new OkHttpClient.Builder()
    .addNetworkInterceptor(new StethoInterceptor())
    .build();Copy the code

HttpURLConnection

If you use HttpURLConnection, said a bit troublesome, you can use a Stetho framework SDK provides class StethoURLConnectionManager to diagnose the client network is open, but there are some pits is to pay attention to.

For example, in order for Stetho to report the correct size of the compressed payload to Chrome on the development machine, you need to personally add “accept-Encoding: gzip” to the HTTP/HTTPS request header and process the compressed response data yourself. If you use Okhttp, you don’t have to worry about all this, and the framework takes care of it for you by default.

The reference code is as follows:

private final StethoURLConnectionManager stethoManager; private static final int READ_TIMEOUT_MS = 10000; private static final int CONNECT_TIMEOUT_MS = 15000; private static final String HEADER_ACCEPT_ENCODING = "Accept-Encoding"; private static final String GZIP_ENCODING = "gzip"; private String url = "http://www.figotan.org"; stethoManager = new StethoURLConnectionManager(url); URL url = new URL(url); // Note that this does not actually create a new connection so it is appropriate to // defer preConnect until after the HttpURLConnection instance is configured. Do not // invoke connect, conn.getInputStream, conn.getOutputStream, etc before calling // preConnect! HttpURLConnection conn = (HttpURLConnection)url.openConnection(); try { conn.setReadTimeout(READ_TIMEOUT_MS); conn.setConnectTimeout(CONNECT_TIMEOUT_MS); conn.setRequestMethod(request.method.toString()); // Adding this disables transparent gzip compression so that we can intercept // the raw stream and display the correct response body size. conn.setRequestProperty(HEADER_ACCEPT_ENCODING, GZIP_ENCODING); SimpleRequestEntity requestEntity = null; if (request.body ! = null) { requestEntity = new ByteArrayRequestEntity(request.body); } stethoManager.preConnect(conn, requestEntity); try { if (request.method == HttpMethod.POST) { if (requestEntity == null) { throw new IllegalStateException("POST requires an entity"); } conn.setDoOutput(true); requestEntity.writeTo(conn.getOutputStream()); } // Ensure that we are connected after this point. Note that getOutputStream above will // also connect and exchange HTTP messages. conn.connect(); stethoManager.postConnect(); } catch (IOException inner) { // This must only be called after preConnect. Failures before that cannot be // represented since the request has not yet begun according to Stetho. stethoManager.httpExchangeFailed(inner); throw inner; } } catch (IOException outer) { conn.disconnect(); throw outer; } try { ByteArrayOutputStream out = new ByteArrayOutputStream(); InputStream rawStream = conn.getInputStream(); try { // Let Stetho see the raw, possibly compressed stream. rawStream = stethoManager.interpretResponseStream(rawStream); if (rawStream ! = null && GZIP_ENCODING.equals(conn.getContentEncoding())) { decompressedStream = new GZIPInputStream(in); } else { decompressedStream = rawStream; } if (decompressedStream ! = null) { int n; byte[] buf = new byte[1024]; while ((n = decompressedStream.read(buf)) ! = -1) { out.write(buf, 0, n); } } } finally { if (rawStream ! = null) { rawStream.close(); } } } finally { conn.disconnect(); }Copy the code

With the above steps, you can already make your APP support network monitoring, database monitoring, and SharedPreferences file content monitoring. If you want to play more advanced versions, see the custom Dumpapp plugin and Rhino below, and if you want to play directly, read on.

It’s also easy to use

The steps are as follows:

  1. Start by running the APP on your phone

  2. Make sure your phone is connected to the developer by USB, and open Chrome on the developer

  3. Enter a value in the Address box of Chromechrome://inspect, you will see the following picture. If your APP is not in the picture, please go back to the above to check if the code access is correct

  4. Click next to APPinspectIf you’ve ever used Chrome’s developer tools, will this look familiar? By the way, this window is Chrome’s built-in developer tool, but instead of monitoring the web, it’s monitoring the APP

  5. Let’s look at the first TAB in the function navigation bar, called “Elements”, and see if what’s in the workspace looks familiar,Hierarchy ViewerClick on the specific XML node to see the corresponding UI control highlighted on the connected phone, which analyzes the nested Hierarchy of APP pages in the same way that the Hierarchy Viewer does

  6. The second TAB is called “Network” and is used for Network monitoring. It basically covers all the function points of “Network Inspection “in Chrome Developer Tools, including previewing downloaded images, viewing JSON data, and web requests and returns

  7. The third TAB is “Sources” to view the details of the web page

  8. Skip the “Timeline” and “Profiles” to view the sixth TAB and “Resources”. As the name indicates, this is the place to view the data generated within the APP. Currently, there are two types of data supported, one is the database (ContentProvider and Sql) data. The other is SharedPreferences data

  9. The “Audits” skip, like “Timeline” and “Profiles”, are currently under-supported and open to further exploration.

  10. “Console” said the old driver

Have a pit?

There are some fields that need to be noted about network monitoring. For details, you can go to the official Chrome Developer Tools documentation

Here is only a detailed explanation of the meanings of the fields in the figure above.

  • Name/Path Name and URL Path of network resources, such as www.figotan.org/c/v/logo.jp. For this network resource, Name is logo.jpg and Path is www.figotan.org/c/v/

  • Method Specifies the HTTP request Method, such as GET and POST

  • Status/Text Indicates the return code specified by the HTTP protocol and the description of the return code, for example, 200/OK

  • Type Specifies the MIME Type of the requested resource, such as Application/JSON image/ JPEG image/ PNG

  • Initiator a request object, can be a Parser/Redirect/Script/Other, see the official documentation

  • Size/Content Size indicates the sum of the header and data body of the HTTP response, which is returned by the remote server. Content is the decoded size of the returned resource

  • Time/Latentcy Time is the total interval between the Time the request is initiated and the last byte returned by the server is received. Latency is the time at which the first byte returned by the server is received

  • Timeline shows a waterfall stream of all network requests

What else can you do

You can do a lot more than monitor the network and view/modify the data, because Stetho has reserved two interfaces for sustainable development

Customize the Dumpapp plug-in

Custom plugins are the preferred way to get old drivers Dumpapp new skills and can be easily added during the configuration process. To add a custom plug-in, simply add the following code:

Stetho.initialize(Stetho.newInitializerBuilder(context)
        .enableDumpapp(new DumperPluginsProvider() {
          @Override
          public Iterable get() {
            return new Stetho.DefaultDumperPluginsBuilder(context)
                .provide(new HelloWorldDumperPlugin())
                .provide(new APODDumperPlugin(context.getContentResolver()))
                .finish();
          }
        })
        .enableWebKitInspector(new ExtInspectorModulesProvider(context))
        .build());Copy the code

Among them, HelloWorldDumperPlugin and APODDumperPlugin are self-defined plug-ins. The specific content can be referred to the sample program provided by Stetho. To execute dumpapp command, first remove the latest code from Git, then find the Dumpapp script and execute it

$git clone https://github.com/facebook/stetho.git $CD stetho / / list of supported commands (plug-in) $. / scripts/dumpapp - p com.facebook.stetho.sample -lCopy the code

Write dumpapp plug-in with reference to sample code, and then use dumpapp command to verify the effect of the plug-in

Stetho support for JavaScript

Stetho’s JavaScript support is currently supported by Rhino, which is developed by Mozilla.

The first plug-in extension method using Dumpapp is powerful and omnipotent, but it requires a certain amount of technology and time cost to complete one thing. It has to go through a series of compilation, compilation, construction, installation, debugging and modification of the code, and then the next cycle. Only after several iterations can the output be formed. This is actually a drawback of non-dynamic languages like C/C ++/ Java, which take too long to develop. So, if there is a written support scripting language can release, actually for r&d efficiency, there is a big promotion, such as the lua/javascript/perl/python/groovy, etc., such light language, without having to compile, finish can release verification, can even write while debugging the edge line.

Chrome Developer Tools supports JavaScript natively, so Stetho also provides JavaScript support.

Rhino is a JavaScript implementation that runs inside Java programs, developed and released as an open source project by Mozilla.

Let’s talk about integration and usage

If you want your APP to support Rhino, the gradle configuration is the first step

Dependencies {the compile 'com. Facebook. Stetho: stetho - js - rhino: 1.3.1'}Copy the code

You can then use the developer tools “Console” driver provided by Chrome on the developer machine (any tool has the Console) to send JavaScript code as follows:

importPackage(android.widget);
importPackage(android.os);
var handler = new Handler(Looper.getMainLooper());
handler.post(function() { Toast.makeText(context, "Hello from JavaScript", Toast.LENGTH_LONG).show() });Copy the code

The running effect is as follows:

If you want to pass variables, classes, closures, and functions to the JavaScript runtime through your APP, you can add the following code when Stetho initializes:

Stetho.initialize(Stetho.newInitializerBuilder(context)
        .enableWebKitInspector(new InspectorModulesProvider() {
          @Override
          public Iterable get() {
            return new DefaultInspectorModulesBuilder(context).runtimeRepl(
                new JsRuntimeReplFactoryBuilder(context)
                    // Pass to JavaScript: var foo = "bar";
                    .addVariable("foo", "bar")
                    .build()
            ).finish();
          }
        })
        .build());Copy the code

For more gameplay, please go to Rhino on Stetho

The resources

Stetho official documentation Stetho source code Stetho: A new debugging platform for Android A First Glance at Stetho tool Remote Debugging on Android with Chrome Chrome DevTools Overview