loading...

Multiple Network environment configuration in iOS: Staging, proxy and localhost

quangdecember profile image Quang ・2 min read

Making network request is a common task in iOS app development. If your company has its own backend team, it's likely that there's different environments you have to set up for your network code: usually Staging & Production environment. There might be some differences between those:

  • Staging might use HTTP while Production always use HTTPS
  • You might need to launch a localhost server
  • Your staging domain and production domain is different
  • Your Staging domain needs a special proxy config.

Here's how to handle those differences using iOS's built-in URLSession:

Understanding URLComponents

URLComponents is a type-safe tool to parse URL information to scheme (HTTPS), host (domain), URL path and query items; and helping you constructing a URL from those elements, with percent encoding included.
Intitialize URLComponents with this convenient extension:

extension URLComponents {
    init(scheme: String, host: String, path: String, queryItems: [URLQueryItem]) {
        self.init()
        self.scheme = scheme
        self.host = host
        self.path = path
        self.queryItems = queryItems
    }
}

Let's create an enum for the scheme we will handle

enum URLScheme : String {
    case HTTPS = "https"
    case HTTP = "http"
}

Configure environments

Staging domain

It's obvious from the URLComponents type that property .scheme will take HTTP or HTTPS and property .host will take your special domain for staging

Local host

For a local host server, you also need to configure the port, where URLComponents.port come in:

self.host = "localhost"
self.scheme = URLScheme.HTTP.rawValue // "HTTP"
self.port = 8080

Special proxy

If your company requires a special proxy in a special Wifi for testing Staging server or internal stuffs, you probably had to deal with iPhone's Wifi settings:

However, this kind of config also make the phone unable to connect to the Internet. Fortunately, you can always add an embedded proxy to any URLSessionConfiguration by taking advantage of property .connectionProxyDictionary.

public func getProxyConfig() -> URLSessionConfiguration {
        let proxyConfiguration = URLSessionConfiguration.default
        proxyConfiguration.requestCachePolicy = URLRequest.CachePolicy.reloadIgnoringLocalCacheData
        proxyConfiguration.connectionProxyDictionary = [AnyHashable: Any]()
        proxyConfiguration.connectionProxyDictionary?[kCFNetworkProxiesHTTPEnable as String] = 1
        proxyConfiguration.connectionProxyDictionary?[kCFNetworkProxiesHTTPProxy as String] = "your.company.internal.domain"
        proxyConfiguration.connectionProxyDictionary?[kCFNetworkProxiesHTTPPort as String] = 9502
        proxyConfiguration.connectionProxyDictionary?[kCFStreamPropertyHTTPSProxyHost as String] = "your.company.internal.domain"
        proxyConfiguration.connectionProxyDictionary?[kCFStreamPropertyHTTPSProxyPort as String] = 9502
        proxyConfiguration.timeoutIntervalForRequest = 30.0
        proxyConfiguration.timeoutIntervalForResource = 60.0
        return proxyConfiguration
    }

kCFStreamPropertyHTTPSProxyHost, kCFNetworkProxiesHTTPProxy is for HTTP Proxy Server. kCFNetworkProxiesHTTPPort and kCFStreamPropertyHTTPSProxyPort is for HTTP Proxy Port.

Finally, with newly created URLSessionConfiguration instance, using +[NSURLSession sessionWithConfiguration:] or URLSession.init(configuration: URLSessionConfiguration) to create your own URLSession. Use this new URLSession for your own network calls, and the rest, including web views, system services stay connecting to the Internet normally.

Enjoy your testable networking code!!!

Posted on by:

quangdecember profile

Quang

@quangdecember

iOS dev, love Swift, love beautiful & well-designed apps, currently an SDK dev

Discussion

pic
Editor guide
 

Good Article taking a similar approach but I can't get it to work, do you know if this approach is still valid on iOS 13.5 ? URLSession goes via proxy as expected when running from playground but the same code stop to work when on the simulator.