Using WiFi is more complicated when trying to use IPification Authentication. By default, all operating systems favor WiFi over cellular connections for all traffic. However, for IPification, the API request must be made using the cellular connection. We realize that users are unlikely to turn off WiFi, so the following code is provided for both iOS and Android to include in your applications. This will allow a small payload to be delivered over the cellular interface, even when WiFi is connected. Telcos usually don’t charge (zero rate) our Authentication URLs, so end users won’t incur any cost.
| Area | Description |
|---|---|
examples/android/request-scoped |
Recommended Android cellular request example |
examples/android/process-scoped |
Advanced Android whole-process cellular binding |
examples/ios/request-scoped |
iOS cellular NWConnection example |
samples/android/process-binding-ip-check |
Runnable Android whole-process routing verification app |
docs |
Platform integration and configuration guides |
im-authentication/android |
Android IM authentication example |
device-info |
SIM and mobile-network device information snippets |
deprecated |
Historical examples retained for reference only |
Request-scoped routing is recommended for IPification. Process-scoped routing affects every future network connection created in the Android application process.
Files moved from the previous layout are listed in MOVED_FILES.md, along
with their compatibility policy.
The following will allow Android applications using Android API 21+ to use Cellular for the API request.
Android 5.0 (API 21) and up
User’s device has the mobile network enabled.
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />OKHttp3 version 5 (supports IPv6/v4).
We use OKHttp3 because it supports binding to the cellular network via socket and targeting DNS.
implementation 'com.squareup.okhttp3:okhttp:5.3.2'
Here's a function that can simplify the action of preferring certain types of networks for your application
val builder: NetworkRequest.Builder = NetworkRequest.Builder()
builder.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET);
builder.addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR);After this you receive an onAvailable() callback and can route the required request through
the returned Network instance.
val mNetworkCallBack = object: ConnectivityManager.NetworkCallback() {
override fun onAvailable(network: Network) {
super.onAvailable(network)
// TODO: process the connection via this network instance ${network}
}
override fun onUnavailable() {
super.onUnavailable()
}
override fun onLost(network: Network) {
super.onLost(network)
}
}val manager = mContext.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
manager.requestNetwork( builder.build(), mNetworkCallBack)More Detail here: Android integration guide
Android 6.0 (API 23) and newer can make cellular the default network for future sockets and DNS lookups in the current app process. This has broad side effects, so request-scoped routing remains the recommended approach for IPification.
For iOS 12 and newer, we use NetWork framework to make network connection via cellular interface.
iOS does not provide a public API that forces the entire app process onto cellular. Interface selection must be applied to connections controlled by the app.
Using the following would be the correct approach to force the connection over cellular:
let tcpOptions = NWProtocolTCP.Options()
let params = NWParameters(tls: enableTLS ? options : nil, tcp: tcpOptions)
params.requiredInterfaceType = .cellular
self.connection = NWConnection.init(host: host , port: port, using: params)After the connection moves into the .ready state and the connection is setup on pdp_ip0 (cell)
connection.stateUpdateHandler = { (newState) in
print("TCP state change to: \(newState)")
switch newState {
case .ready:
print("ready")
// self.delegate!.didConnect(socket: self)
break
case .waiting(let error):
print("waiting error \(error.debugDescription ?? "")")
break
case .failed(let error):
print("failed \(error.debugDescription ?? "")")
// self.delegate?.didDisconnect(socket: self, error: error)
break
case .cancelled:
print("cancelled" )
break
default:
print("default")
break
}
}
connection.start(queue: .main)More detail: iOS integration guide