iOS: Our First Pod

Diego Urquiza
Johnson & Johnson Open Source
4 min readMay 15, 2019

It’s 3pm on a Monday and you’re testing an app on your phone. You try to update a form and run into a network error. Now it’s time to find the culprit. You start up your debugger and investigate. A few minutes later you discover it’s a 400 response. You gather all the network data to share with the backend team to see what’s going on. After some strategic copy and paste-ing into slack they can now test your request.

Sharing network requests from your mobile iOS project with the rest of your team can be unnecessarily difficult. Usually you would go with a paid third-party solution that is bloated with features you don’t care about. Wouldn’t it be nice if you could have an in-app solution that is easy to integrate and use? Imagine shaking your phone and viewing your network data then sharing it with ease. Are you excited yet?

Johnson & Johnson is proud to announce our latest open source project, Guppy.

What is Guppy?

Guppy is an open source iOS library that helps with logging data. The core functionality of Guppy is logging network requests/responses and being able to share them with ease. When creating Guppy, we wanted to create a tool that any developer can integrate with their project in minutes with ease. For packing and distributing the library we choose to use Cocoapods since it is widely popular for iOS developers.

Why did we make Guppy?

Resources for testers is typically not an issue at J&J since we have large teams. However, we did see a huge gap in our manual testing cycle where testers were not sure if a bug was a data issue or mobile app issue. We considered using Charles for testers but our internal J&J network is locked down so it wouldn’t work. We thought building something in-app that could display network requests and be easily shared across the team would be incredibly helpful. Thus, Guppy was born.

Why Open Source?

At J&J, we’re big fans of using open source libraries to speed up our POCs and we want to give back to the community. We’ve been using Guppy for a few months internally and we think it can be a useful tool for developers. In order to continue improving Guppy, we’d like your help and feedback on how to enhance Guppy going forward. We have a few ideas already, but we’re curious to see what the community thinks.

How does Guppy work?

Getting Guppy to display within an app from anywhere is simple. We just have to hook it into the current window of the application and listen to shake gestures. The developer using Guppy can disable this feature and choose what events should trigger Guppy to appear.

Intercepting and logging packages is a harder challenge. Apple has very useful APIs that a developer can tap into in order to choose how URLSession handles requests and responses. This is done by creating a configuration for your URLSession and setting Guppy’s SniffURLProtocol class as one of the protocol classes for the configuration. If you’re using the shared URLSession, Guppy has a convenience method registerURLProtocol() that you can call with no extra setup needed.

SniffURLProtocol is where all the magic happens. You need to conform to URLProtocol, URLSessionDataDelegate and URLSessionTaskDelegate in order to control how tasks are handled by URLSession. In the case of Guppy, we don’t want to change how the requests and responses are working, we just want to listen for the data. Below you can find the core methods in SniffURLProtocol that are used to gather a Guppy Network Log. For the entire implementation you can checkout SniffURLProtocol.swift.

Creating the Network Log with SniffURLProtocol.swift

The Request:

- URL Protocol instance has the request property available.

The Request Body:

init(request: URLRequest, cachedResponse: CachedURLResponse?, client: URLProtocolClient?)

- Get the Request body if there is one.

The Response:

optional func urlSession(_ session: URLSession, dataTask: URLSessionDataTask, didReceive response: URLResponse, completionHandler: @escaping (URLSession.ResponseDisposition) -> Void)

- Here we get the response back and we can choose if we want to allow it, cancel it, or convert it into a download. We always want to allow it so we solely capture the response object for Guppy.

The Response Data:

optional func urlSession(_ session: URLSession, dataTask: URLSessionDataTask, didReceive data: Data)

- This method gives us data that is being received. This might trigger multiple times if the response data is large so we make sure to append new data if needed.

The Log:

func stopLoading()

- Our request is stopped/done. Here we gather all the data associated with the request/response and send it to Guppy to log.

Future Features/Enhancements

1. Enhance searching. Searching works now… Kind of.

2. Custom Logging. Right now logging was created with just networking in mind but it would be nice to log anything as a developer.

3. JSON prettify. We do have some formatting but we can do better.

Resources

1. https://www.raywenderlich.com/2292-using-nsurlprotocol-with-swift

2. https://developer.apple.com/documentation/foundation/urlprotocol

Closing Thoughts

I hope this post was helpful and insightful on how Guppy works. We’re extremely excited on beginning a new open source movement at J&J. Be on the look out for future projects and updates to Guppy. Thank you for reading!

--

--