Section 12/181 menit
12. Network Debugging: Proxyman & Charles
12. Network Debugging: Proxyman & Charles
Proxyman (Direkomendasikan untuk macOS)
swift
# Install
brew install --cask proxyman
# atau download dari proxymam.io
# Setup:
# 1. Buka Proxyman → Install Certificate (untuk HTTPS decryption)
# 2. Di simulator: Settings → General → VPN & Device Management → Trust certificate
# 3. Di device fisik: Settings → Wi-Fi → (i) → Configure Proxy → Manual
# Host: IP Mac, Port: 9090
# Fitur Proxyman yang berguna:
# - Breakpoint: intercept & edit request/response sebelum dikirim
# - Map Local: ganti response dengan file lokal (untuk mock)
# - Map Remote: redirect URL ke URL lain
# - Repeat: kirim ulang request
# - Scripting: modifikasi request/response dengan JavaScript
swift
// Proxyman Script: tambahkan header ke semua request
function onRequest(context, url, request) {
request.headers["X-Debug-Mode"] = "true";
request.headers["X-App-Version"] = "2.0.0";
return request;
}
// Proxyman Script: mock response untuk endpoint tertentu
function onResponse(context, url, request, response) {
if (url.includes("/api/products")) {
response.body = JSON.stringify({
products: [
{ id: "1", name: "Mock Product", price: 99000 }
]
});
response.statusCode = 200;
}
return response;
}
Charles Proxy: Alternative dengan Lebih Banyak Fitur Enterprise
swift
Charles setup:
1. Help → SSL Proxying → Install Charles Root Certificate
2. Proxy → SSL Proxying Settings → Add: *.api.myapp.com
3. Di device: WiFi → (i) → HTTP Proxy → Manual → Charles IP:8888
Fitur Charles yang tidak ada di Proxyman:
- Throttle network speed (simulasi 3G/EDGE)
- AMF/SOAP support
- DNS Spoofing
- Lebih stable untuk high-traffic load testing
URLProtocol untuk In-App Network Monitoring (No Extra Tool)
swift
// Gunakan ini untuk logging network di app sendiri tanpa tools eksternal
// Berguna untuk QA atau debug build
class NetworkMonitorProtocol: URLProtocol {
override class func canInit(with request: URLRequest) -> Bool {
// Intercept semua HTTP/HTTPS requests
return URLProtocol.property(forKey: "intercepted", in: request) == nil
}
override class func canonicalRequest(for request: URLRequest) -> URLRequest {
return request
}
override func startLoading() {
let mutableRequest = (request as NSURLRequest).mutableCopy() as! NSMutableURLRequest
URLProtocol.setProperty(true, forKey: "intercepted", in: mutableRequest)
let start = Date()
URLSession.shared.dataTask(with: mutableRequest as URLRequest) { data, response, error in
let duration = Date().timeIntervalSince(start) * 1000
if let httpResponse = response as? HTTPURLResponse {
print("""
[Network] \(self.request.httpMethod ?? "GET") \(self.request.url?.absoluteString ?? "")
Status: \(httpResponse.statusCode)
Duration: \(String(format: "%.0f", duration))ms
Size: \(data?.count ?? 0) bytes
""")
}
if let error {
self.client?.urlProtocol(self, didFailWithError: error)
} else {
self.client?.urlProtocol(self, didReceive: response!, cacheStoragePolicy: .allowed)
if let data { self.client?.urlProtocol(self, didLoad: data) }
self.client?.urlProtocolDidFinishLoading(self)
}
}.resume()
}
override func stopLoading() {}
}
// Register di AppDelegate atau saat setup testing
URLProtocol.registerClass(NetworkMonitorProtocol.self)