Multiple Network environment configuration in iOS: Staging, proxy and localhost
Tags: ios, swift, urlsession, xcode
Published: 2020-03-04 16:11:24


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:

```swift
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

```swift
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:

```swift
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:

![](https://www.howtogeek.com/wp-content/uploads/2017/02/ximg_589e4b52038ab.png.pagespeed.gp+jp+jw+pj+ws+js+rj+rp+rw+ri+cp+md.ic.zbURe1qhUT.png)

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`. 

```swift
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!!!