diff --git a/Package.swift b/Package.swift index 01d3e94..2c5ccbb 100644 --- a/Package.swift +++ b/Package.swift @@ -2,7 +2,7 @@ // The swift-tools-version declares the minimum version of Swift required to build this package. /* - * Copyright (C) 2020 Groupe MINASTE + * Copyright (C) 2021 Groupe MINASTE * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/README.md b/README.md index a57c0ca..d6ff3fc 100644 --- a/README.md +++ b/README.md @@ -47,7 +47,7 @@ FMNetwork: (contains every data about a SIM card and its connected network) * mnc: String (returns the Mobile Network Code (MNC) of the SIM card carrier, "--" by default) * land: String (returns the uppercased 2-digit ISO country code* of the SIM card carrier, "--" by default) * type: FMNetworkType (.sim, .esim or .current) - * plmns: [PLMN] (returns the list of mcc and mnc of the declared roaming PLMNs, [] by default ) + * plmns: [PLMN] (returns the list of mcc and mnc of the declared roaming PLMNs, [] by default) * network: FMNetworkData (contains every data about the connected network of a SIM card) * name: String (returns the name of the connected network, "Carrier" by default) * mcc: String (returns the Mobile Country Code (MCC) of the connected network, "---" by default) @@ -77,13 +77,18 @@ FMNetwork: (contains every data about a SIM card and its connected network) * roam5G: Bool? (returns the declared 5G national roaming status, nil by default) * chasedmnc: String? (returns the MNC used to detect the national roaming network - if mnc, requires a speedtest to detect the national roaming, mnc/nil by default) * nrdec: Bool? (returns the national roaming declaration status - if true, chasedmnc = mnc, false/nil by default) - +* device: FMNetworkDevice (contains all the data about the device, independently from the mobile network) + * currentWifiNetwork: WIFI? (returns all the data about the currently connected Wi-Fi network, if the prerequisites are satisfied, nil by default) + * isOnPhoneCall: Bool (retruns the call status, for phone calls as well as VoIP apps using CallKit, false by default) + * isConnectedToNetwork: Bool (returns the Internet connection status, no matter how) + * isOnAirplaneMode: Bool (returns the Airplane Mode toggle status for the device) + *There is an exception for International carriers. They might return the non-standardised 2-digits code "WD", standing for World. ### To access the full documentation, you can use the Quick Help feature in Xcode. Simply Command + click on any property of the FMNetwork item you wrote, and click on Show Quick Help to view the entire documentation for that code. ## Licence -Copyright (C) 2020 Groupe MINASTE +Copyright (C) 2021 Groupe MINASTE This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/Sources/FMNetwork/Extensions/StringExtension.swift b/Sources/FMNetwork/Extensions/StringExtension.swift index 20fe082..15e5bcf 100644 --- a/Sources/FMNetwork/Extensions/StringExtension.swift +++ b/Sources/FMNetwork/Extensions/StringExtension.swift @@ -1,5 +1,5 @@ /* - * Copyright (C) 2020 Groupe MINASTE + * Copyright (C) 2021 Groupe MINASTE * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/Sources/FMNetwork/FMNetwork.swift b/Sources/FMNetwork/FMNetwork.swift index 016869c..a58c63d 100644 --- a/Sources/FMNetwork/FMNetwork.swift +++ b/Sources/FMNetwork/FMNetwork.swift @@ -1,5 +1,5 @@ /* - * Copyright (C) 2020 Groupe MINASTE + * Copyright (C) 2021 Groupe MINASTE * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -43,6 +43,9 @@ public class FMNetwork { /// - Note: Make sure you verify that card.active is equal to true before processing any data returned by the FMNetwork object. public var fmobile: FMobileService? + /// This property contains every function to get data about the current device, independently from the mobile network. + public var device: FMNetworkDevice + /// Initialize an FMNetwork object. Retrieves all the data for a given SIM card type. /// - Parameter type: SIM card type.

/// There are three options available : @@ -52,7 +55,7 @@ public class FMNetwork { /// /// - Note: If you select .current as the type, the SIM card type returned in the FMNetwork property will very likely change to .sim or .esim accordingly. In case the card.type property still returns current on the FMNetwork object, it means FMNetwork couldn't identify the SIM card and the data returned are likely to be incorrect. Make sure you check the card.active property on the FMNetwork object first, to make sure the SIM card is in use and therefore identified. public init(type: FMNetworkType) { - (card, network) = FMNetwork.createFMNetwork(type) + (card, network, device) = FMNetwork.createFMNetwork(type) } /// Initialize the fmobile property using the official FMobile API service, in case you want complementary data about a SIM card. Keep in mind the FMobile API service requires an active Internet connection, and is working in async. You are fully responsible of the mobile data consumed by this function. The function completes in async with a Boolean, indicating whether the retrieve of the complementary data via the FMobile API service was successful or not. @@ -102,7 +105,7 @@ public class FMNetwork { /// Internal function to construct an FMNetwork object, with a given SIM card type. /// - Parameter type: SIM card type (.sim, .esim or .current) /// - Returns: A couple of FMNetworkSIMData and FMNetworkData to be inserted in the respective FMNetwork class variables - internal static func createFMNetwork(_ type: FMNetworkType) -> (FMNetworkSIMData, FMNetworkData) { + internal static func createFMNetwork(_ type: FMNetworkType) -> (FMNetworkSIMData, FMNetworkData, FMNetworkDevice) { var type = type var card: FMNetworkSIMData @@ -206,7 +209,6 @@ public class FMNetwork { if #available(iOS 11.0, *) { test = try NSDictionary(contentsOf: url, error: ()) } else { - // Fallback on earlier versions test = NSDictionary(contentsOf: url) ?? NSDictionary() } let array = test["StatusBarImages"] as? NSArray ?? NSArray.init(array: [0]) @@ -225,7 +227,6 @@ public class FMNetwork { if #available(iOS 11.0, *) { testsim = try NSDictionary(contentsOf: urlcarrier, error: ()) } else { - // Fallback on earlier versions testsim = NSDictionary(contentsOf: urlcarrier) ?? NSDictionary() } let arraysim = testsim["StatusBarImages"] as? NSArray ?? NSArray.init(array: [0]) @@ -307,7 +308,9 @@ public class FMNetwork { card.land = CarrierIdentification.getIsoCountryCode(card.mcc, card.mnc) network.land = CarrierIdentification.getIsoCountryCode(network.mcc, network.mnc) - return (card, network) + let device = FMNetworkDevice() + + return (card, network, device) } } diff --git a/Sources/FMNetwork/Utilities/FMNetwork/FMNetworkData.swift b/Sources/FMNetwork/Utilities/FMNetwork/FMNetworkData.swift index 7b6b88b..1ca63f3 100644 --- a/Sources/FMNetwork/Utilities/FMNetwork/FMNetworkData.swift +++ b/Sources/FMNetwork/Utilities/FMNetwork/FMNetworkData.swift @@ -1,5 +1,5 @@ /* - * Copyright (C) 2020 Groupe MINASTE + * Copyright (C) 2021 Groupe MINASTE * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/Sources/FMNetwork/Utilities/FMNetwork/FMNetworkDevice.swift b/Sources/FMNetwork/Utilities/FMNetwork/FMNetworkDevice.swift new file mode 100644 index 0000000..8fcaa52 --- /dev/null +++ b/Sources/FMNetwork/Utilities/FMNetwork/FMNetworkDevice.swift @@ -0,0 +1,168 @@ +/* + * Copyright (C) 2021 Groupe MINASTE + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + */ +// +// FMNetworkDevice.swift +// FMobile +// +// Created by PlugN on 01/07/2020. +// Copyright © 2020 Groupe MINASTE. All rights reserved. +// + +import Foundation +import CoreTelephony +import CallKit +import SystemConfiguration.CaptiveNetwork +import NetworkExtension + +/// This class contains every data about the device, independently from the mobile network. +public class FMNetworkDevice { + + + /// This property contains the data of the currently connected Wi-Fi Network. If the property is not nil, it means the device is connected to a Wi-Fi Network. You can use that property in combination with the isConnectedToNetwork() function to determine whether the device is using cellular data, however be aware that you will not be 100% sure that the device will be using cellular data, as Bluetooth and Ethernet adapters are also possible network connection sources. Defaults to nil. + /// - Attention: This property requires the "Access Wifi Information" capability enabled on your target, as well as an authorized access to location to be initialized properly. The property being nil does not mean that the device is disconnected from the Wi-Fi network if these requirements are not satisfied. + /// - Warning: Prior to iOS 14.0, only the SSID and BSSID values are available. Make sure you check that the detailedDataAvailable variable equals true before reading any other variable. + public var currentWifiNetwork: WIFI? + + /// This property is equal true if a phone call is detected, whether it is using the mobile network, or Internet VoIP services using CallKit. + public var isOnPhoneCall: Bool + + /// This property is equal true if the device is connected to Internet, no matter how. You can use that property in combination with the currentWifiNetwork property to determine whether the device is using cellular data, however be aware that you will not be 100% sure that the device will be using cellular data, as Bluetooth and Ethernet adapters are also possible network connection sources. + public var isConnectedToNetwork: Bool + + /// This property stores the Boolean value of whether the device is in Airplane Mode or not. + public var isOnAirplaneMode: Bool + + + // DEPRECATED SECTION -------------------------------------- + + + // OBSOLETED SECTION --------------------------------------- + + + // INTERNAL SECTION ---------------------------------------- + + + /// This function returns true if a phone call is detected, whether it is using the mobile network, or Internet VoIP services using CallKit. + /// - Returns: The Boolean phone call status. Defaults to false. + internal class func isOnPhoneCall() -> Bool { + if #available(iOS 10.0, *) { + for call in CXCallObserver().calls { + if call.hasEnded == false { + return true + } + } + } else { + let callCenter = CTCallCenter() + for call in callCenter.currentCalls ?? [] { + if call.callState == CTCallStateConnected { + return true + } + } + } + return false + } + + /// This function returns true if the device is connected to Internet, no matter how. You can use that function in combination with the isWifiConnected() function to determine whether the device is using cellular data, however be aware that you will not be 100% sure that the device will be using cellular data, as Bluetooth and Ethernet adapters are also possible network connection sources. + /// - Returns: The Boolean Internet connection status. Returns false by default. + internal class func isConnectedToNetwork() -> Bool { + var zeroAddress = sockaddr_in() + zeroAddress.sin_len = UInt8(MemoryLayout.size(ofValue: zeroAddress)) + zeroAddress.sin_family = sa_family_t(AF_INET) + + let defaultRouteReachability = withUnsafePointer(to: &zeroAddress) { + $0.withMemoryRebound(to: sockaddr.self, capacity: 1) {zeroSockAddress in + SCNetworkReachabilityCreateWithAddress(nil, zeroSockAddress) + } + } + + if let defaultRouteReachability = defaultRouteReachability { + var flags : SCNetworkReachabilityFlags = [] + + if !SCNetworkReachabilityGetFlags(defaultRouteReachability, &flags) { + return false + } + + let isReachable = flags.contains(.reachable) + let needsConnection = flags.contains(.connectionRequired) + return (isReachable && !needsConnection) + } + + return false + } + + /// This function returns whether the device is in Airplane Mode or not. + /// - Returns: The Boolean Airplane Mode toggle status. Returns false by default. + internal class func isOnAirplaneMode() -> Bool { + let urlairplane = URL(fileURLWithPath: "/var/preferences/SystemConfiguration/com.apple.radios.plist") + do { + let test: NSDictionary + if #available(iOS 11.0, *) { + test = try NSDictionary(contentsOf: urlairplane, error: ()) + } else { + test = NSDictionary(contentsOf: urlairplane) ?? NSDictionary() + } + let airplanemode = test["AirplaneMode"] as? Bool ?? false + return airplanemode + } catch { + return false + } + } + + + /// - Attention: This function should stay internal. It is used to fetch the current Wi-Fi data, and should not be called outside of the class. Please refer to the corresponding public functions to fetch the data you need. + /// - Returns: status: The boolean value indicating whether the Wi-Fi is connected or not (defaults to false), ssid, bssid and ssiddata as String (defaults to "") + @available (iOS, obsoleted: 14.0) + internal class func getWifiDataOlder() -> (status: Bool, ssid: String, bssid: String) { + if let interface = CNCopySupportedInterfaces() { + for i in 0 ..< CFArrayGetCount(interface) { + let interfaceName: UnsafeRawPointer = CFArrayGetValueAtIndex(interface, i) + let rec = unsafeBitCast(interfaceName, to: AnyObject.self) + if let unsafeInterfaceData = CNCopyCurrentNetworkInfo("\(rec)" as CFString), let interfaceData = unsafeInterfaceData as? [String : AnyObject] { + return (true, interfaceData["SSID"] as? String ?? "", interfaceData["BSSID"] as? String ?? "") + } else { + print("Not connected to wifi.") + return (false, "", "") + } + } + } + return (false, "", "") + } + + /// - Attention: This function should stay internal. It intitializes the class, but is intended to be called while generating an FMNetwork object. This function is not supposed to be called separetly. + internal init() { + + self.isOnPhoneCall = FMNetworkDevice.isOnPhoneCall() + self.isOnAirplaneMode = FMNetworkDevice.isOnAirplaneMode() + self.isConnectedToNetwork = FMNetworkDevice.isConnectedToNetwork() + + if #available(iOS 14.0, *) { + NEHotspotNetwork.fetchCurrent { (network) in + if let network = network { + self.currentWifiNetwork = WIFI(network: network) + } + } + } else { + let wifiData = FMNetworkDevice.getWifiDataOlder() + if wifiData.status && wifiData.bssid != "" && wifiData.bssid != "00:00:00:00:00:00" { + self.currentWifiNetwork = WIFI(ssid: wifiData.ssid, bssid: wifiData.bssid) + } + } + } + +} diff --git a/Sources/FMNetwork/Utilities/FMNetwork/FMNetworkSIMData.swift b/Sources/FMNetwork/Utilities/FMNetwork/FMNetworkSIMData.swift index e03c95c..ac5be9a 100644 --- a/Sources/FMNetwork/Utilities/FMNetwork/FMNetworkSIMData.swift +++ b/Sources/FMNetwork/Utilities/FMNetwork/FMNetworkSIMData.swift @@ -1,5 +1,5 @@ /* - * Copyright (C) 2020 Groupe MINASTE + * Copyright (C) 2021 Groupe MINASTE * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/Sources/FMNetwork/Utilities/FMNetwork/FMNetworkType.swift b/Sources/FMNetwork/Utilities/FMNetwork/FMNetworkType.swift index 072d08f..478f0b4 100644 --- a/Sources/FMNetwork/Utilities/FMNetwork/FMNetworkType.swift +++ b/Sources/FMNetwork/Utilities/FMNetwork/FMNetworkType.swift @@ -1,5 +1,5 @@ /* - * Copyright (C) 2020 Groupe MINASTE + * Copyright (C) 2021 Groupe MINASTE * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/Sources/FMNetwork/Utilities/Other/AnyCodable.swift b/Sources/FMNetwork/Utilities/Other/AnyCodable.swift index ebb3d57..9e6ebbd 100644 --- a/Sources/FMNetwork/Utilities/Other/AnyCodable.swift +++ b/Sources/FMNetwork/Utilities/Other/AnyCodable.swift @@ -1,5 +1,5 @@ /* - * Copyright (C) 2020 Groupe MINASTE + * Copyright (C) 2021 Groupe MINASTE * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/Sources/FMNetwork/Utilities/Other/CarrierIdentification.swift b/Sources/FMNetwork/Utilities/Other/CarrierIdentification.swift index 6cc64c8..ef23bc6 100644 --- a/Sources/FMNetwork/Utilities/Other/CarrierIdentification.swift +++ b/Sources/FMNetwork/Utilities/Other/CarrierIdentification.swift @@ -1,5 +1,5 @@ /* - * Copyright (C) 2020 Groupe MINASTE + * Copyright (C) 2021 Groupe MINASTE * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/Sources/FMNetwork/Utilities/Other/FMobileService.swift b/Sources/FMNetwork/Utilities/Other/FMobileService.swift index c78ae0b..f4f8891 100644 --- a/Sources/FMNetwork/Utilities/Other/FMobileService.swift +++ b/Sources/FMNetwork/Utilities/Other/FMobileService.swift @@ -1,5 +1,5 @@ /* - * Copyright (C) 2020 Groupe MINASTE + * Copyright (C) 2021 Groupe MINASTE * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/Sources/FMNetwork/Utilities/Other/PLMN.swift b/Sources/FMNetwork/Utilities/Other/PLMN.swift index b2c313f..99e59fb 100644 --- a/Sources/FMNetwork/Utilities/Other/PLMN.swift +++ b/Sources/FMNetwork/Utilities/Other/PLMN.swift @@ -1,5 +1,5 @@ /* - * Copyright (C) 2020 Groupe MINASTE + * Copyright (C) 2021 Groupe MINASTE * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -18,9 +18,10 @@ */ // // PLMN.swift -// +// FMNetwork // -// Created by PlugN on 21.12.20.. +// Created by PlugN on 21/12/2020. +// Copyright © 2020 Groupe MINASTE. All rights reserved. // import Foundation diff --git a/Sources/FMNetwork/Utilities/Other/WIFI.swift b/Sources/FMNetwork/Utilities/Other/WIFI.swift new file mode 100644 index 0000000..98e4fd9 --- /dev/null +++ b/Sources/FMNetwork/Utilities/Other/WIFI.swift @@ -0,0 +1,99 @@ +/* + * Copyright (C) 2021 Groupe MINASTE + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + */ +// +// WIFI.swift +// FMNetwork +// +// Created by PlugN on 01/01/2021. +// Copyright © 2021 Groupe MINASTE. All rights reserved. +// + +import Foundation +import NetworkExtension + +public class WIFI { + + /// The String name (SSID) for the Wi-Fi Network. + public var ssid: String + + /// The String ID (BSSID) for the Wi-Fi Network. + public var bssid: String + + /// The Boolean value indicating if more detailed data are available. If this value is equal to false, you should only read the SSID and BSSID values. Prior to iOS 14.0, this value will always be false. + public var detailedDataAvailable: Bool + + /// The Double Signal Strength for the Wi-Fi Network. + /// - Warning: Prior to iOS 14.0, only the SSID and BSSID values are available. Make sure you check that the detailedDataAvailable variable equals true before reading any other variable. + public var signalStrength: Double + + /// The Boolean Security status for the Wi-Fi Network. + /// - Warning: Prior to iOS 14.0, only the SSID and BSSID values are available. Make sure you check that the detailedDataAvailable variable equals true before reading any other variable. + public var isSecure: Bool + + /// The Boolean Auto Join status for the Wi-Fi Network. + /// - Warning: Prior to iOS 14.0, only the SSID and BSSID values are available. Make sure you check that the detailedDataAvailable variable equals true before reading any other variable. + public var didAutoJoin: Bool + + /// The Boolean Just Joined status for the Wi-Fi Network. + /// - Warning: Prior to iOS 14.0, only the SSID and BSSID values are available. Make sure you check that the detailedDataAvailable variable equals true before reading any other variable. + public var didJustJoin: Bool + + /// The Boolean Choosen Helper status for the Wi-Fi Network. This applies only if your application works with this specific NEHotspotNetwork as a Helper. Otherwise, it returns false. + /// - Warning: Prior to iOS 14.0, only the SSID and BSSID values are available. Make sure you check that the detailedDataAvailable variable equals true before reading any other variable. + public var isChoosenHelper: Bool + + + // DEPRECATED SECTION -------------------------------------- + + + // OBSOLETED SECTION --------------------------------------- + + + // INTERNAL SECTION ---------------------------------------- + + + /// - Attention: This function should stay internal. It intitializes the class, but is intended to be called while generating an FMNetwork object. This function is not supposed to be called separetly. + /// - Parameters: + /// - ssid: The SSID of the Wi-Fi network + /// - bssid: The BSSID of the Wi-Fi Network + internal init(ssid: String, bssid: String) { + self.ssid = ssid + self.bssid = bssid + self.detailedDataAvailable = false + self.signalStrength = 0 + self.isSecure = false + self.didAutoJoin = false + self.didJustJoin = false + self.isChoosenHelper = false + } + + + /// - Attention: This function should stay internal. It intitializes the class, but is intended to be called while generating an FMNetwork object. This function is not supposed to be called separetly. + /// - Parameter network: The NEHotspotNetwork object (for iOS 14.0+) + internal init(network: NEHotspotNetwork) { + self.ssid = network.ssid + self.bssid = network.bssid + self.detailedDataAvailable = true + self.signalStrength = network.signalStrength + self.isSecure = network.isSecure + self.didAutoJoin = network.didAutoJoin + self.didJustJoin = network.didJustJoin + self.isChoosenHelper = network.isChosenHelper + } +} diff --git a/Tests/FMNetworkTests/FMNetworkTests.swift b/Tests/FMNetworkTests/FMNetworkTests.swift index 665865d..4390449 100644 --- a/Tests/FMNetworkTests/FMNetworkTests.swift +++ b/Tests/FMNetworkTests/FMNetworkTests.swift @@ -1,5 +1,5 @@ /* - * Copyright (C) 2020 Groupe MINASTE + * Copyright (C) 2021 Groupe MINASTE * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/Tests/FMNetworkTests/XCTestManifests.swift b/Tests/FMNetworkTests/XCTestManifests.swift index 81ce21e..2a73e6c 100644 --- a/Tests/FMNetworkTests/XCTestManifests.swift +++ b/Tests/FMNetworkTests/XCTestManifests.swift @@ -1,5 +1,5 @@ /* - * Copyright (C) 2020 Groupe MINASTE + * Copyright (C) 2021 Groupe MINASTE * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/Tests/LinuxMain.swift b/Tests/LinuxMain.swift index dd1563f..9498c0f 100644 --- a/Tests/LinuxMain.swift +++ b/Tests/LinuxMain.swift @@ -1,5 +1,5 @@ /* - * Copyright (C) 2020 Groupe MINASTE + * Copyright (C) 2021 Groupe MINASTE * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by