How to determine the iOS connection type (Edge, 3G, 4G, Wifi)? [duplicate]
Asked Answered
A

9

28

How is it possible to determine the iOS connection type?

I want to know if there is Edge, 3G, 4G oder Wifi available at this moment on my device.

This information I need to load different data with a different size.

So, I don't want to load an image of 4 MB with a connection type "Edge".

Arjun answered 9/12, 2014 at 13:19 Comment(1)
check this github.com/Isuru-Nanayakkara/Swift-ReachabilityVladi
C
26

For swift we can use following function:

func getNetworkType()->String {
    do{
        let reachability:Reachability = try Reachability.reachabilityForInternetConnection()
        do{
            try reachability.startNotifier()
            let status = reachability.currentReachabilityStatus
            if(status == .NotReachable){
                return ""
            }else if (status == .ReachableViaWiFi){
                return "Wifi"
            }else if (status == .ReachableViaWWAN){
                let networkInfo = CTTelephonyNetworkInfo()
                let carrierType = networkInfo.currentRadioAccessTechnology
                switch carrierType{
                case CTRadioAccessTechnologyGPRS?,CTRadioAccessTechnologyEdge?,CTRadioAccessTechnologyCDMA1x?: return "2G"
                case CTRadioAccessTechnologyWCDMA?,CTRadioAccessTechnologyHSDPA?,CTRadioAccessTechnologyHSUPA?,CTRadioAccessTechnologyCDMAEVDORev0?,CTRadioAccessTechnologyCDMAEVDORevA?,CTRadioAccessTechnologyCDMAEVDORevB?,CTRadioAccessTechnologyeHRPD?: return "3G"
                case CTRadioAccessTechnologyLTE?: return "4G"
                default: return ""
                }


            }else{
                return ""
            }
        }catch{
            return ""
        }

    }catch{
        return ""
    }


}
Coalfish answered 6/4, 2016 at 12:28 Comment(5)
I believe this requires Reachability library and CoreTelephony.Lemur
Hey, thanks for your input. I cleaned the whole thing up and introduced a small enum b/c I didn't like the (empty) String return type. Just sharing in case anybody wants to use this: gist.github.com/floriankrueger/46e6f9f4c910b5313a72b358fdad25ccGravy
This throws Expression pattern of type 'String' cannot match values of type '[String : String]' errors in Swift 5Jala
Thanks this works for me, the currentRadioAccessTechnology is now serviceCurrentRadioAccessTechnologyTiticaca
There are cleaner ways. without reachability etc...Polydeuces
M
10

Swift 5, iOS 12.0 or later:

import SystemConfiguration
import CoreTelephony
import Foundation

class func getConnectionType() -> String {
        guard let reachability = SCNetworkReachabilityCreateWithName(kCFAllocatorDefault, "www.google.com") else {
            return "NO INTERNET"
        }

        var flags = SCNetworkReachabilityFlags()
        SCNetworkReachabilityGetFlags(reachability, &flags)

        let isReachable = flags.contains(.reachable)
        let isWWAN = flags.contains(.isWWAN)

        if isReachable {
            if isWWAN {
                let networkInfo = CTTelephonyNetworkInfo()
                let carrierType = networkInfo.serviceCurrentRadioAccessTechnology

                guard let carrierTypeName = carrierType?.first?.value else {
                    return "UNKNOWN"
                }

                switch carrierTypeName {
                case CTRadioAccessTechnologyGPRS, CTRadioAccessTechnologyEdge, CTRadioAccessTechnologyCDMA1x:
                    return "2G"
                case CTRadioAccessTechnologyLTE:
                    return "4G"
                default:
                    return "3G"
                }
            } else {
                return "WIFI"
            }
        } else {
            return "NO INTERNET"
        }
    }
Mchugh answered 20/4, 2020 at 16:50 Comment(5)
I know its too soon for that but is there any way to detect 5G connections on iPhone 12+ ?Unguinous
I think that it's no possible yet, because the last Radio Access Technology value that Apple defiined was the CTRadioAccessTechnologyLTE. But, you could test the following: CTRadioAccessTechnologyGPRS, CTRadioAccessTechnologyEdge, CTRadioAccessTechnologyCDMA1x -> 2g. CTRadioAccessTechnologyWCDMA, CTRadioAccessTechnologyHSDPA, CTRadioAccessTechnologyHSUPA, CTRadioAccessTechnologyCDMAEVDORev0, CTRadioAccessTechnologyCDMAEVDORevA, CTRadioAccessTechnologyCDMAEVDORevB, CTRadioAccessTechnologyeHRPD -> 3G CTRadioAccessTechnologyLTE -> 4G else -> 5G.Etz
That makes sense for you?Etz
I can't test it because in Argentina we still don't have a 5G connections haha.Etz
for 5G there is now CTRadioAccessTechnologyNRNSA and CTRadioAccessTechnologyNRWistrup
A
5

CoreTelephony.framework is needed.

let networkInfo = CTTelephonyNetworkInfo()
let networkString = networkInfo.currentRadioAccessTechnology

if networkString == CTRadioAccessTechnologyLTE{
  // LTE (4G)
}else if networkString == CTRadioAccessTechnologyWCDMA{
  // 3G 
}else if networkString == CTRadioAccessTechnologyEdge{
  // EDGE (2G)
}
Ammonify answered 15/7, 2016 at 7:5 Comment(2)
what is "telefonyInfo" ?Neela
it's about the user’s cellular service provider which means I will be not able to check if the connection type is on wifi, right?Surname
H
5

in Objective C:

first import @import CoreTelephony.

Reachability *reachability = [Reachability reachabilityForInternetConnection];

    [reachability startNotifier];

    NetworkStatus status = [reachability currentReachabilityStatus];

    if(status == NotReachable)
    {
        //No internet
    }
    else if (status == ReachableViaWiFi)
    {
        //WiFi
    }
    else if (status == ReachableViaWWAN)
    {
        CTTelephonyNetworkInfo *netinfo = [[CTTelephonyNetworkInfo alloc] init];
        NSString * carrierType = netinfo.currentRadioAccessTechnology;
        if ([carrierType isEqualToString:CTRadioAccessTechnologyGPRS]) {
//             @"2G";
        } else if ([carrierType isEqualToString:CTRadioAccessTechnologyEdge]) {
//             @"2G";
        } else if ([carrierType isEqualToString:CTRadioAccessTechnologyWCDMA]) {
//             @"3G";
        } else if ([carrierType isEqualToString:CTRadioAccessTechnologyHSDPA]) {
//             @"3G";
        } else if ([carrierType isEqualToString:CTRadioAccessTechnologyHSUPA]) {
//             @"3G";
        } else if ([carrierType isEqualToString:CTRadioAccessTechnologyCDMA1x]) {
//             @"2G";
        } else if ([carrierType isEqualToString:CTRadioAccessTechnologyCDMAEVDORev0]) {
//             @"3G";
        } else if ([carrierType isEqualToString:CTRadioAccessTechnologyCDMAEVDORevA]) {
//             @"3G";
        } else if ([carrierType isEqualToString:CTRadioAccessTechnologyCDMAEVDORevB]) {
//             @"3G";
        } else if ([carrierType isEqualToString:CTRadioAccessTechnologyeHRPD]) {
//             @"3G";
        } else if ([carrierType isEqualToString:CTRadioAccessTechnologyLTE]) {
//             @"4G";
        }

    }
Holmes answered 14/12, 2016 at 9:56 Comment(0)
T
3

You can use CTTelephonyNetworkInfo class from Apple. You can use this API on iOS 7+

You need to import it : @import CoreTelephony

Trusteeship answered 24/8, 2015 at 9:14 Comment(2)
This will not tell you if the phone is on a WiFi connection - in that case the CTTelephonyNetworkInfo object you declare will be nil, if there is no carrier.Adhesion
it would have been helpful to provide either a link or a snippet to this answer: as it is, it provides less information than a Google search (which, one opes, the OP has already done).Wherry
A
2
import CoreTelephony

enum RadioAccessTechnology: String {
    case cdma = "CTRadioAccessTechnologyCDMA1x"
    case edge = "CTRadioAccessTechnologyEdge"
    case gprs = "CTRadioAccessTechnologyGPRS"
    case hrpd = "CTRadioAccessTechnologyeHRPD"
    case hsdpa = "CTRadioAccessTechnologyHSDPA"
    case hsupa = "CTRadioAccessTechnologyHSUPA"
    case lte = "CTRadioAccessTechnologyLTE"
    case rev0 = "CTRadioAccessTechnologyCDMAEVDORev0"
    case revA = "CTRadioAccessTechnologyCDMAEVDORevA"
    case revB = "CTRadioAccessTechnologyCDMAEVDORevB"
    case wcdma = "CTRadioAccessTechnologyWCDMA"

    var description: String {
        switch self {
        case .gprs, .edge, .cdma:
            return "2G"
        case .lte:
            return "4G"
        default:
            return "3G"
        }
    }
}    

// Example:
let networkInfo = CTTelephonyNetworkInfo()
let networkString = networkInfo.currentRadioAccessTechnology
let tecnology = RadioAccessTechnology(rawValue: networkString)

print(tecnology.description)
Anthony answered 18/7, 2017 at 19:28 Comment(2)
This returns 4G when you're connected via wi-fiPakistan
You should add CustomStringConvertible to your RadioAccessTechnology declaration to be able to print your objects instead of accessing its description property.Needful
T
2

A Quick update Xcode : 10.2.1

Update swift 4.2 :

func updateUserInterface() {
    switch Network.reachability.status {
    case .unreachable:
        view.backgroundColor = .black
        alertNoReachable("Network Unreachable", "Please check The Settings")
    case .wwan:
        self.imageNoConnection.isHidden = true
        let networkInfo = CTTelephonyNetworkInfo()
        let carrierType = networkInfo.serviceCurrentRadioAccessTechnology
        //print (carrierType?[0])
        // CTRadioAccessTechnologyLTE
        if carrierType!.first(where: { (_, value) in value.contains("CTRadioAccessTechnologyLTE") }) != nil {
            self.networkType = "4G"
             print ("Wwan : 4G")
           // view.backgroundColor = .magenta
        }
            // 2g CTRadioAccessTechnologyGPRS?,CTRadioAccessTechnologyEdge?,CTRadioAccessTechnologyCDMA1x?
        else if carrierType!.first(where: { (_, value) in value.contains("CTRadioAccessTechnologyGPRS") }) != nil || carrierType!.first(where: { (_, value) in value.contains("CTRadioAccessTechnologyEdge") }) != nil  || carrierType!.first(where: { (_, value) in value.contains("CTRadioAccessTechnologyCDMA1x") }) != nil {
            self.networkType = "2G"
            print("Wwan : 2G")
            //view.backgroundColor = .gray
        }
          // 3g CTRadioAccessTechnologyWCDMA?,CTRadioAccessTechnologyHSDPA?,CTRadioAccessTechnologyHSUPA?,CTRadioAccessTechnologyCDMAEVDORev0?,CTRadioAccessTechnologyCDMAEVDORevA?,CTRadioAccessTechnologyCDMAEVDORevB?,CTRadioAccessTechnologyeHRPD?
        else if carrierType!.first(where: { (_, value) in value.contains("CTRadioAccessTechnologyWCDMA") }) != nil || carrierType!.first(where: { (_, value) in value.contains("CTRadioAccessTechnologyHSDPA") }) != nil  || carrierType!.first(where: { (_, value) in value.contains("CTRadioAccessTechnologyHSUPA") }) != nil || carrierType!.first(where: { (_, value) in value.contains("CTRadioAccessTechnologyCDMAEVDORev0") }) != nil  || carrierType!.first(where: { (_, value) in value.contains("CTRadioAccessTechnologyCDMAEVDORevA") }) != nil || carrierType!.first(where: { (_, value) in value.contains("CTRadioAccessTechnologyCDMAEVDORevB") }) != nil || carrierType!.first(where: { (_, value) in value.contains("CTRadioAccessTechnologyeHRPD") }) != nil  {
            self.networkType = "3G"
            print ("Wwan : 3G")
            //view.backgroundColor = .red
        }
    case .wifi:
        self.imageNoConnection.isHidden = true
        self.networkType = "WiFi"
       // view.backgroundColor = .green
    }
    print("Reachability Summary")
    print("Status:", Network.reachability.status)
    print("HostName:", Network.reachability.hostname ?? "nil")
    print("Reachable:", Network.reachability.isReachable)
    print("Wifi:", Network.reachability.isReachableViaWiFi)
}
@objc func statusManager(_ notification: Notification) {
    updateUserInterface()
}

Reachability.swift

import Foundation
import SystemConfiguration

class Reachability {
    var hostname: String?
    var isRunning = false
    var isReachableOnWWAN: Bool
    var reachability: SCNetworkReachability?
    var reachabilityFlags = SCNetworkReachabilityFlags()
    let reachabilitySerialQueue = DispatchQueue(label: "ReachabilityQueue")
    init?(hostname: String) throws {
        guard let reachability = SCNetworkReachabilityCreateWithName(nil, hostname) else {
            throw Network.Error.failedToCreateWith(hostname)
        }
        self.reachability = reachability
        self.hostname = hostname
        isReachableOnWWAN = true
        try start()
    }
    init() throws {
        var zeroAddress = sockaddr_in()
        zeroAddress.sin_len = UInt8(MemoryLayout<sockaddr_in>.size)
        zeroAddress.sin_family = sa_family_t(AF_INET)
        guard let reachability = withUnsafePointer(to: &zeroAddress, {
            $0.withMemoryRebound(to: sockaddr.self, capacity: 1) {
                SCNetworkReachabilityCreateWithAddress(nil, $0)
            }
        }) else {
            throw Network.Error.failedToInitializeWith(zeroAddress)
        }

        self.reachability = reachability
        isReachableOnWWAN = true

        try start()
    }

    var status: Network.Status {
        return  !isConnectedToNetwork ? .unreachable :
                isReachableViaWiFi    ? .wifi :
                isRunningOnDevice     ? .wwan : .unreachable
    }

    var isRunningOnDevice: Bool = {
        #if targetEnvironment(simulator)
            return false
        #else
            return true
        #endif
    }()
    deinit { stop() }
}


extension Reachability {

    func start() throws {
        guard let reachability = reachability, !isRunning else { return }
        var context = SCNetworkReachabilityContext(version: 0, info: nil, retain: nil, release: nil, copyDescription: nil)
        context.info = Unmanaged<Reachability>.passUnretained(self).toOpaque()
        guard SCNetworkReachabilitySetCallback(reachability, callout, &context) else { stop()
            throw Network.Error.failedToSetCallout
        }
        guard SCNetworkReachabilitySetDispatchQueue(reachability, reachabilitySerialQueue) else { stop()
            throw Network.Error.failedToSetDispatchQueue
        }
        reachabilitySerialQueue.async { self.flagsChanged() }
        isRunning = true
    }

    func stop() {
        defer { isRunning = false }
        guard let reachability = reachability else { return }
        SCNetworkReachabilitySetCallback(reachability, nil, nil)
        SCNetworkReachabilitySetDispatchQueue(reachability, nil)
        self.reachability = nil
    }

    var isConnectedToNetwork: Bool {
        return isReachable &&
               !isConnectionRequiredAndTransientConnection &&
               !(isRunningOnDevice && isWWAN && !isReachableOnWWAN)
    }

    var isReachableViaWiFi: Bool {
        return isReachable && isRunningOnDevice && !isWWAN
    }

    /// Flags that indicate the reachability of a network node name or address, including whether a connection is required, and whether some user intervention might be required when establishing a connection.
    var flags: SCNetworkReachabilityFlags? {
        guard let reachability = reachability else { return nil }
        var flags = SCNetworkReachabilityFlags()
        return withUnsafeMutablePointer(to: &flags) {
            SCNetworkReachabilityGetFlags(reachability, UnsafeMutablePointer($0))
            } ? flags : nil
    }

    /// compares the current flags with the previous flags and if changed posts a flagsChanged notification
    func flagsChanged() {
        guard let flags = flags, flags != reachabilityFlags else { return }
        reachabilityFlags = flags
        NotificationCenter.default.post(name: .flagsChanged, object: self)
    }

    /// The specified node name or address can be reached via a transient connection, such as PPP.
    var transientConnection: Bool { return flags?.contains(.transientConnection) == true }

    /// The specified node name or address can be reached using the current network configuration.
    var isReachable: Bool { return flags?.contains(.reachable) == true }

    /// The specified node name or address can be reached using the current network configuration, but a connection must first be established. If this flag is set, the kSCNetworkReachabilityFlagsConnectionOnTraffic flag, kSCNetworkReachabilityFlagsConnectionOnDemand flag, or kSCNetworkReachabilityFlagsIsWWAN flag is also typically set to indicate the type of connection required. If the user must manually make the connection, the kSCNetworkReachabilityFlagsInterventionRequired flag is also set.
    var connectionRequired: Bool { return flags?.contains(.connectionRequired) == true }

    /// The specified node name or address can be reached using the current network configuration, but a connection must first be established. Any traffic directed to the specified name or address will initiate the connection.
    var connectionOnTraffic: Bool { return flags?.contains(.connectionOnTraffic) == true }

    /// The specified node name or address can be reached using the current network configuration, but a connection must first be established.
    var interventionRequired: Bool { return flags?.contains(.interventionRequired) == true }

    /// The specified node name or address can be reached using the current network configuration, but a connection must first be established. The connection will be established "On Demand" by the CFSocketStream programming interface (see CFStream Socket Additions for information on this). Other functions will not establish the connection.
    var connectionOnDemand: Bool { return flags?.contains(.connectionOnDemand) == true }

    /// The specified node name or address is one that is associated with a network interface on the current system.
    var isLocalAddress: Bool { return flags?.contains(.isLocalAddress) == true }

    /// Network traffic to the specified node name or address will not go through a gateway, but is routed directly to one of the interfaces in the system.
    var isDirect: Bool { return flags?.contains(.isDirect) == true }

    /// The specified node name or address can be reached via a cellular connection, such as EDGE or GPRS.
    var isWWAN: Bool { return flags?.contains(.isWWAN) == true }

    /// The specified node name or address can be reached using the current network configuration, but a connection must first be established. If this flag is set
    /// The specified node name or address can be reached via a transient connection, such as PPP.
    var isConnectionRequiredAndTransientConnection: Bool {
        return (flags?.intersection([.connectionRequired, .transientConnection]) == [.connectionRequired, .transientConnection]) == true
    }
}



func callout(reachability: SCNetworkReachability, flags: SCNetworkReachabilityFlags, info: UnsafeMutableRawPointer?) {
    guard let info = info else { return }
    DispatchQueue.main.async {
        Unmanaged<Reachability>
            .fromOpaque(info)
            .takeUnretainedValue()
            .flagsChanged()
    }
}

extension Notification.Name {
    static let flagsChanged = Notification.Name("FlagsChanged")
}


struct Network {
    static var reachability: Reachability!
    enum Status: String {
        case unreachable, wwan, wifi

    }
    enum Error: Swift.Error {
        case failedToSetCallout
        case failedToSetDispatchQueue
        case failedToCreateWith(String)
        case failedToInitializeWith(sockaddr_in)
    }
}

AppDelegate.swift

import UIKit
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?


func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
    // Override point for customization after application launch.

    // network reachable
    do {
        try Network.reachability = Reachability(hostname: "www.google.com")
    }
    catch {
        switch error as? Network.Error {
        case let .failedToCreateWith(hostname)?:
            print("Network error:\nFailed to create reachability object With host named:", hostname)
        case let .failedToInitializeWith(address)?:
            print("Network error:\nFailed to initialize reachability object With address:", address)
        case .failedToSetCallout?:
            print("Network error:\nFailed to set callout")
        case .failedToSetDispatchQueue?:
            print("Network error:\nFailed to set DispatchQueue")
        case .none:
            print(error)
        }
    }
    //
    return true
}

func applicationWillResignActive(_ application: UIApplication) {
    // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
    // Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game.
}

func applicationDidEnterBackground(_ application: UIApplication) {
    // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
    // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
}

func applicationWillEnterForeground(_ application: UIApplication) {
    // Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background.
}

func applicationDidBecomeActive(_ application: UIApplication) {
    // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
}

func applicationWillTerminate(_ application: UIApplication) {
    // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
}

}

source

Titicaca answered 21/5, 2019 at 14:34 Comment(0)
T
0

I found a good modular swift implementation that doesn't rely on any third party library, it's pretty straightforward, and pretty lightwaight. It's available HERE, but for the sake of completion, here's the code:

//
//  NetStatus.swift
//  NetStatusDemo
//
//  Created by Gabriel Theodoropoulos.
//  Copyright © 2019 Appcoda. All rights reserved.
//

import Foundation
import Network

class NetStatus {

    // MARK: - Properties

    static let shared = NetStatus()

    var monitor: NWPathMonitor?

    var isMonitoring = false

    var didStartMonitoringHandler: (() -> Void)?

    var didStopMonitoringHandler: (() -> Void)?

    var netStatusChangeHandler: (() -> Void)?


    var isNetStatusConnected: Bool {
        guard let monitor = monitor else { return false }
        return monitor.currentPath.status == .satisfied
    }


    var interfaceType: NWInterface.InterfaceType? {
        guard let monitor = monitor else { return nil }

        return monitor.currentPath.availableInterfaces.filter {
            monitor.currentPath.usesInterfaceType($0.type) }.first?.type
    }


    var availableInterfacesTypes: [NWInterface.InterfaceType]? {
        guard let monitor = monitor else { return nil }
        return monitor.currentPath.availableInterfaces.map { $0.type }
    }


    var isExpensive: Bool {
        return monitor?.currentPath.isExpensive ?? false
    }


    // MARK: - Init & Deinit

    private init() {

    }


    deinit {
        stopMonitoring()
    }


    // MARK: - Method Implementation

    func startMonitoring() {
        guard !isMonitoring else { return }

        monitor = NWPathMonitor()
        let queue = DispatchQueue(label: "NetStatus_Monitor")
        monitor?.start(queue: queue)

        monitor?.pathUpdateHandler = { _ in
            self.netStatusChangeHandler?()
        }

        isMonitoring = true
        didStartMonitoringHandler?()
    }


    func stopMonitoring() {
        guard isMonitoring, let monitor = monitor else { return }
        monitor.cancel()
        self.monitor = nil
        isMonitoring = false
        didStopMonitoringHandler?()
    }

}
Tampere answered 3/2, 2020 at 1:13 Comment(1)
This is a really good and clean solution for check if device is connected to internet, but doesn't solve the problem exposed by the user.Elodea
R
0

I found this implementation, using the iOS 12.0+ serviceCurrentRadioAccessTechnology and a switch statement, suits my needs.

@objc var getCellularNetworkType: String {  
    guard (monitor != nil) else { return "" }
    guard isCellular else { return "" }
    let networkInfo = CTTelephonyNetworkInfo()
    let carrierTypeString = networkInfo.serviceCurrentRadioAccessTechnology!.values.first!
    switch carrierTypeString {
    case CTRadioAccessTechnologyGPRS,CTRadioAccessTechnologyEdge,CTRadioAccessTechnologyCDMA1x: return "2G"
    case CTRadioAccessTechnologyWCDMA,CTRadioAccessTechnologyHSDPA,CTRadioAccessTechnologyHSUPA,CTRadioAccessTechnologyCDMAEVDORev0,CTRadioAccessTechnologyCDMAEVDORevA,CTRadioAccessTechnologyCDMAEVDORevB,CTRadioAccessTechnologyeHRPD: return "3G"
    case CTRadioAccessTechnologyLTE: return "4G"
    default: return ""
    }
}
Refrigeration answered 14/4, 2020 at 16:12 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.