Cómo detectar la intensidad de la señal de red en iOS Accesibilidad

Estoy creando una nueva aplicación itinerante en iOS, esta aplicación depende en gran medida de Maps e incluirá dos mapas.

  1. Mi primer mapa funcionará cuando el usuario tenga una señal de red fuerte (mapas de Apple).
  2. Mi segundo mapa se usará cuando no haya ninguna red o realmente baja (Offline MapBox).

¿Por qué tengo dos mapas diferentes en una aplicación? Mi aplicación es una aplicación de dirección, por lo que cuando el usuario tiene una red realmente baja o ninguna, irá a Map MapBox sin conexión. Además, Apple Maps tendrá integración con Yelp y no Map MapBox fuera de línea.

Entonces mi Pregunta: ¿Cómo puedo detectar la señal de red en WiFi, 4G Lte y 3G? Imagen fuera de línea de MapBox

Mi idea original era cronometrar la descarga de un archivo y ver cuánto tiempo lleva:

 @interface ViewController ()  @property (nonatomic) CFAbsoluteTime startTime; @property (nonatomic) CFAbsoluteTime stopTime; @property (nonatomic) long long bytesReceived; @property (nonatomic, copy) void (^speedTestCompletionHandler)(CGFloat megabytesPerSecond, NSError *error); @end @implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; [self testDownloadSpeedWithTimout:5.0 completionHandler:^(CGFloat megabytesPerSecond, NSError *error) { NSLog(@"%0.1f; error = %@", megabytesPerSecond, error); }]; } /// Test speed of download /// /// Test the speed of a connection by downloading some predetermined resource. Alternatively, you could add the /// URL of what to use for testing the connection as a parameter to this method. /// /// @param timeout The maximum amount of time for the request. /// @param completionHandler The block to be called when the request finishes (or times out). /// The error parameter to this closure indicates whether there was an error downloading /// the resource (other than timeout). /// /// @note Note, the timeout parameter doesn't have to be enough to download the entire /// resource, but rather just sufficiently long enough to measure the speed of the download. - (void)testDownloadSpeedWithTimout:(NSTimeInterval)timeout completionHandler:(nonnull void (^)(CGFloat megabytesPerSecond, NSError * _Nullable error))completionHandler { NSURL *url = [NSURL URLWithString:@"http://insert.your.site.here/yourfile"]; self.startTime = CFAbsoluteTimeGetCurrent(); self.stopTime = self.startTime; self.bytesReceived = 0; self.speedTestCompletionHandler = completionHandler; NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration ephemeralSessionConfiguration]; configuration.timeoutIntervalForResource = timeout; NSURLSession *session = [NSURLSession sessionWithConfiguration:configuration delegate:self delegateQueue:nil]; [[session dataTaskWithURL:url] resume]; } - (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveData:(NSData *)data { self.bytesReceived += [data length]; self.stopTime = CFAbsoluteTimeGetCurrent(); } - (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error { CFAbsoluteTime elapsed = self.stopTime - self.startTime; CGFloat speed = elapsed != 0 ? self.bytesReceived / (CFAbsoluteTimeGetCurrent() - self.startTime) / 1024.0 / 1024.0 : -1; // treat timeout as no error (as we're testing speed, not worried about whether we got entire resource or not if (error == nil || ([error.domain isEqualToString:NSURLErrorDomain] && error.code == NSURLErrorTimedOut)) { self.speedTestCompletionHandler(speed, nil); } else { self.speedTestCompletionHandler(speed, error); } } @end 

Tenga en cuenta que esto mide la velocidad, incluida la latencia de inicio de la conexión. Alternativamente, podría inicializar startTime en didReceiveResponse , si quería didReceiveResponse importancia a esa latencia inicial.


Una vez hecho esto, en retrospectiva, no me gusta perder tiempo o ancho de banda descargando algo que no tiene ningún beneficio práctico para la aplicación. Entonces, como alternativa, podría sugerir un enfoque mucho más pragmático: ¿por qué no intentas abrir un MKMapView y ver cuánto tiempo lleva terminar de descargar el mapa? Si falla o si demora más de una cierta cantidad de tiempo, cambia a tu mapa sin conexión. De nuevo, hay bastante variabilidad aquí (no solo porque el ancho de banda de la red y la latencia, sino también porque algunas imágenes de mapas parecen estar en caché), así que asegúrese de configurar kMaximumElapsedTime para que sea lo suficientemente grande como para manejar todas las permutaciones razonables de un conexión exitosa (es decir, no seas demasiado agresivo al usar un valor bajo).

Para hacer esto, solo asegúrese de configurar su controlador de vista para que sea el delegate de MKMapView . Y luego puedes hacer:

 @interface ViewController ()  @property (nonatomic, strong) NSDate *startDate; @end static CGFloat const kMaximumElapsedTime = 5.0; @implementation ViewController // insert the rest of your implementation here #pragma mark - MKMapViewDelegate methods - (void)mapViewWillStartLoadingMap:(MKMapView *)mapView { NSDate *localStartDate = [NSDate date]; self.startDate = localStartDate; double delayInSeconds = kMaximumElapsedTime; dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayInSeconds * NSEC_PER_SEC)); dispatch_after(popTime, dispatch_get_main_queue(), ^(void){ // Check to see if either: // (a) start date property is not nil (because if it is, we // finished map download); and // (b) start date property is the same as the value we set // above, as it's possible this map download is done, but // we're already in the process of downloading the next // map. if (self.startDate && self.startDate == localStartDate) { [[[UIAlertView alloc] initWithTitle:nil message:[NSString stringWithFormat:@"Map timed out after %.1f", delayInSeconds] delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil] show]; } }); } - (void)mapViewDidFailLoadingMap:(MKMapView *)mapView withError:(NSError *)error { self.startDate = nil; [[[UIAlertView alloc] initWithTitle:nil message:@"Online map failed" delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil] show]; } - (void)mapViewDidFinishLoadingMap:(MKMapView *)mapView { NSTimeInterval elapsed = [[NSDate date] timeIntervalSinceDate:self.startDate]; self.startDate = nil; self.statusLabel.text = [NSString stringWithFormat:@"%.1f seconds", elapsed]; } 

Creo que una búsqueda en Google ayudará.

Busque el siguiente hilo en StackOverflow-

Escaneo wifi de iOS, potencia de la señal

fuerza de la señal de iPhone

Por lo tanto, no creo que todavía pueda hacer esto sin utilizar API privadas.

Para Swift

 class NetworkSpeedProvider: NSObject { var startTime = CFAbsoluteTime() var stopTime = CFAbsoluteTime() var bytesReceived: CGFloat = 0 var speedTestCompletionHandler: ((_ megabytesPerSecond: CGFloat, _ error: Error?) -> Void)? = nil func test() { testDownloadSpeed(withTimout: 5.0, completionHandler: {(_ megabytesPerSecond: CGFloat, _ error: Error?) -> Void in print("%0.1f; error = \(megabytesPerSecond)") }) } } extension NetworkSpeedProvider: URLSessionDataDelegate, URLSessionDelegate { func testDownloadSpeed(withTimout timeout: TimeInterval, completionHandler: @escaping (_ megabytesPerSecond: CGFloat, _ error: Error?) -> Void) { // you set any relevant string with any file let urlForSpeedTest = URL(string: "http://sofes.miximages.com/ios/any.jpg") startTime = CFAbsoluteTimeGetCurrent() stopTime = startTime bytesReceived = 0 speedTestCompletionHandler = completionHandler let configuration = URLSessionConfiguration.ephemeral configuration.timeoutIntervalForResource = timeout let session = URLSession(configuration: configuration, delegate: self, delegateQueue: nil) guard let checkedUrl = urlForSpeedTest else { return } session.dataTask(with: checkedUrl).resume() } func urlSession(_ session: URLSession, dataTask: URLSessionDataTask, didReceive data: Data) { bytesReceived += CGFloat(data.count) stopTime = CFAbsoluteTimeGetCurrent() } func urlSession(_ session: URLSession, task: URLSessionTask, didCompleteWithError error: Error?) { let elapsed = (stopTime - startTime) //as? CFAbsoluteTime let speed: CGFloat = elapsed != 0 ? bytesReceived / (CGFloat(CFAbsoluteTimeGetCurrent() - startTime)) / 1024.0 / 1024.0 : -1.0 // treat timeout as no error (as we're testing speed, not worried about whether we got entire resource or not if error == nil || ((((error as NSError?)?.domain) == NSURLErrorDomain) && (error as NSError?)?.code == NSURLErrorTimedOut) { speedTestCompletionHandler?(speed, nil) } else { speedTestCompletionHandler?(speed, error) } } }