Skip to content

feat(ios): implement URLProtocol-based network interceptor#22

Merged
imsankalp merged 3 commits into
mainfrom
feat/ios-network-interceptor
May 29, 2026
Merged

feat(ios): implement URLProtocol-based network interceptor#22
imsankalp merged 3 commits into
mainfrom
feat/ios-network-interceptor

Conversation

@imsankalp

@imsankalp imsankalp commented May 25, 2026

Copy link
Copy Markdown
Owner

Summary

Brings iOS to full parity with Android. Every fetch / XMLHttpRequest / axios call made through React Native's networking layer is now captured on iOS, stored, and emitted as a NetworkTools:onRequest event — exactly matching the Android behaviour.

New files

File Purpose
ios/NetworkToolsInterceptor.{h,m} NSURLProtocol subclass — intercepts all HTTP/HTTPS URLSession traffic; prevents infinite recursion via a request property key; caps body capture at 256 KB; skips binary MIME types
ios/NetworkToolsStorage.{h,m} Thread-safe NSLock-backed singleton, max 100 requests (mirrors NetworkRequestStorage.kt)
ios/NetworkToolsManager.{h,m} Singleton — +activate registers the URLProtocol (#if DEBUG only); holds a weak RCTEventEmitter reference for JS event emission

Updated files

ios/NetworkTools.h / .mmNetworkTools now extends RCTEventEmitter (in addition to implementing NativeNetworkToolsSpec) so NetworkTools:onRequest events flow through the standard DeviceEventEmitter on both old-arch (bridge) and new-arch (TurboModule/JSI). getTurboModule: retained for new arch.

NetworkTools.podspecNetworkToolsManager.h is now a public header so Swift AppDelegates can call NetworkToolsManager.activate() after import NetworkTools.

Expo pluginapplySwiftAppDelegatePatch and applyObjcAppDelegatePatch added. withNetworkTools now patches both MainApplication (Android) and AppDelegate (iOS) in a single expo prebuild run. Android snippets also updated to include the BuildConfig.DEBUG guard (forward-ports #14/#15).

example/ios/.../AppDelegate.swift#if DEBUG NetworkToolsManager.activate() #endif added.

README.md — iOS marked ✅ Supported; setup instructions cover both platforms.

Architecture

iOS URLSession request
       ↓
NetworkToolsInterceptor.canInitWithRequest:  → YES (http/https, not already handled)
       ↓
startLoading: capture request body, tag request, forward via ephemeral URLSession
       ↓
NSURLSessionDataDelegate callbacks collect response chunks
       ↓
didCompleteWithError: forward to client, call recordWithError:
       ↓
NetworkToolsStorage.addRequest:    (in-memory, thread-safe, max 100)
NetworkToolsManager.emitRequest:   → [RCTEventEmitter sendEventWithName:body:]
       ↓
JS NativeEventEmitter "NetworkTools:onRequest"
       ↓
NetworkMonitorContext → FloatingNetworkMonitor UI

Test plan

  • All 41 JS/plugin tests pass (yarn jest)
  • pod install in example/ios succeeds with the new source files
  • yarn ios on simulator — requests from the example app appear in the floating monitor
  • Release build (xcodebuild -configuration Release) — NetworkToolsManager.activate() is not called (#if DEBUG compiled out), URLProtocol not registered
  • expo prebuild on a fresh Expo iOS project → AppDelegate.swift contains import NetworkTools and the #if DEBUG activation block

Closes #13

imsankalp and others added 3 commits May 25, 2026 23:58
Brings iOS to full parity with Android.

Native layer (6 new files):
- NetworkToolsInterceptor: NSURLProtocol subclass that intercepts all
  HTTP/HTTPS traffic through URLSession (the transport React Native uses
  on iOS). Marks forwarded requests with a property key to prevent
  infinite recursion. Caps response body capture at 256 KB; skips binary
  MIME types entirely.
- NetworkToolsStorage: thread-safe NSLock-backed singleton, max 100
  requests (mirrors NetworkRequestStorage.kt).
- NetworkToolsManager: singleton that owns +activate (registers the
  URLProtocol, #if DEBUG only) and event emission via the module's
  RCTEventEmitter reference.

Module bridge (updated):
- NetworkTools now extends RCTEventEmitter so "NetworkTools:onRequest"
  events flow through the standard DeviceEventEmitter on both old-arch
  (bridge) and new-arch (JSI/TurboModule). getTurboModule: retained for
  new arch.
- NetworkTools.podspec exposes NetworkToolsManager.h as a public header
  so Swift AppDelegates can call NetworkToolsManager.activate() after
  import NetworkTools.

Expo plugin (iOS side added):
- applySwiftAppDelegatePatch: adds import NetworkTools and inserts a
  #if DEBUG NetworkToolsManager.activate() #endif block at the top of
  application(_:didFinishLaunchingWithOptions:).
- applyObjcAppDelegatePatch: same for Objective-C AppDelegate.mm.
- Android snippets also updated to include the BuildConfig.DEBUG guard.
- Plugin tests expanded from 8 to 18; all 41 suite tests pass.

Example app:
- AppDelegate.swift updated with the #if DEBUG activation block.

README: iOS marked as Supported; setup covers both platforms.

Closes #13

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…ation

- Added swizzling of NSURLSessionConfiguration
- Improved request body handling by buffering HTTP body streams and capturing request data.
- Updated NetworkToolsManager to use RCTEventEmitter for event emission.
- Enhanced UI components to display request and response bodies
@imsankalp
imsankalp merged commit 24f29fa into main May 29, 2026
6 of 7 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat(ios): implement URLProtocol-based network interceptor for iOS

1 participant