Most (mobile) applications we develop everyday will interact with other systems through a network. This can be done using various protocols and connection types, we use REST, websockets, mqtt, … And s̶o̶m̶e̶ ̶o̶f̶ a lot of those days we spent working on those applications, we are debugging these interactions with the server.
There are many options and existing solutions, each with their own pros and cons. Some examples include logging HTTP requests and responses to the console (using HttpLoggingInterceptor, for example) or using a proxy such as Charles or Fiddler between our device and server.
However, none of those existing tools ticked all of the boxes for us. We needed something more. Enter: Niddler
Niddler: An integrated network interceptor (for the IntelliJ platform)
Created to fill a desperate need, niddler is a combination of a library and an associated IntelliJ plugin.
- IDE integration: Integrated with (y)our favourite IDE: IntelliJ (and by extension Android Studio). Easily view, search, filter, export your network traces directly from your development environment, no need to switch to external tools
- Technology agnostic: The niddler protocol is not specifically geared towards the standard HTTP communication, in fact it was conceived for debugging high-traffic websocket applications
- Post-factum debugging: The niddler server keeps a (configurable) cache of the latest traffic in memory at all times. Seen something strange while not connected to your development machine? Just connect after-the-fact and inspect traffic from the past.
- Multiple platforms: After the initial library for native android projects (with convenience implementation built-in for okhttp), we also wrote a library specifically for dart/flutter!
- Call site tracing: Curious to see why a specific call was made? Enable call-site stack tracing and get instant insight what part of your code triggered the call. Even works across asynchronous gaps in dart
- No build-time magic: The runtime libraries are regular java/dart libraries that you include and configure. There is no need for special byte code manipulation or special build steps to make it work
- No SSL breaking required: Niddler works by exposing the requests and responses as seen by the application. This means SSL secured connections can keep executing normally without having to add certificates or weakening your connection stack
- Link-layer agnostic: Niddler connections work (most of the time) by proxying data over your USB connection, this means you can debug your network stack even if your test device is only connected over 4G, ethernet, …
Configuring the library
For a detailed description on how to use the plugin, please check out the ‘Niddler IntelliJ plugin’ post here.
You can install it from the IntelliJ plugin marketplace. After installation, a new tool window is available on the bottom of the screen. If you have a niddler server running on a connected device, simply press the ‘play’ icon in the niddler window and watch the magic happen!
Connection magic Architectural overview
High-level niddler architecture diagram
Niddler is split up into two parts: a server library embedded into your application and an IntelliJ plugin. These systems communicate with each other using the so-called niddler protocol over a physical link.
The niddler protocol is an application level protocol that uses websockets as its communication mechanism. This means that the physical layer used by the system can be anything that supports basic TCP connections. Currently implemented in the plugin are a number of ways to establish such a connection, based on the device under test.
When connected to a mobile device using USB, the plugin will create a direct TCP connection by forwarding TCP connections over USB. This connection is established by using ADB forward or libimobiledevice’s iproxy utility. In both cases, creating this connection by using adb over wifi or being remotely connected to your apple tv for example, should also work™.
When you are not debugging a mobile device (or if you are using the ios simulator), the plugin is also capable of connecting to local processes using regular TCP sockets to localhost. In case the device you wish to connect to is on a different machine not currently connected to your development box, there is also the option to directly connect by entering the device’s IP directly.
Because we don’t want to waste time by figuring out which niddler servers are running, on which device and which port they are using, the library and plugin work together to expose this information through a discovery mechanism.
This discovery mechanism works by create an additional TCP server socket in the library on a well-known port (6394) and exposing information about running processes on it.
The details are subject to a deeper dive <coming soon>, but the gist of it is: when you press connect in the plugin, you should see a list of connected devices and for each of these devices which niddler servers are running.