【问题标题】:Using Private API To read WiFi RSSI Value使用私有 API 读取 WiFi RSSI 值
【发布时间】:2017-05-24 20:07:23
【问题描述】:

我正在开发一些不需要在 App Store 上的东西,所以我对使用私有 API 来满足我的需求没有任何问题 我正在尝试使用 MobileWiFi. framework to read the RSSI value for the wireless network the phone is currently connected to. I've included thehttps://github.com/Cykey/ios-reversed-headers/tree/c613e45f3ee5ad9f85ec7d43906cf69ee812ec6a/MobileWiFi` 标头并使用桥接头将它们包含在我的 swift 项目中并编写如下代码。请原谅,我是新手。

import SystemConfiguration.CaptiveNetwork
typealias _WiFiManagerClientCreate = @convention(c) (CFAllocator, CInt) -> UnsafeRawPointer
typealias _WiFiManagerClientCopyDevices = @convention(c) (UnsafeRawPointer) -> CFArray
typealias _WiFiDeviceClientCopyProperty = @convention(c) (UnsafeRawPointer, CFString) -> CFPropertyList

if let libHandle = dlopen (Paths.ipConfiguration, RTLD_LAZY) {
        result = libHandle.debugDescription

        let _createManagerPtr = dlsym(libHandle, "WiFiManagerClientCreate")
        let _clientCopyDevicesPtr = dlsym(libHandle, "WiFiManagerClientCopyDevices")
        let _clientCopyPropertyPtr = dlsym(libHandle, "WiFiDeviceClientCopyProperty")

        if (_createManagerPtr != nil) && (_clientCopyDevicesPtr != nil) && (_clientCopyPropertyPtr != nil) {
            let _createManager = unsafeBitCast(_createManagerPtr, to: _WiFiManagerClientCreate.self)
            let _clientCopyDevices = unsafeBitCast(_clientCopyDevicesPtr, to: _WiFiManagerClientCopyDevices.self)
            let _clientCopyProperty = unsafeBitCast(_clientCopyPropertyPtr, to: _WiFiDeviceClientCopyProperty.self)

            let manager = _createManager(kCFAllocatorDefault, 0)
            let devices = _clientCopyDevices(manager)
            let client = CFArrayGetValueAtIndex(devices, 0)

            let data = _clientCopyProperty(client!, "RSSI" as CFString)
            let rssi = CFDictionaryGetValue(data as! CFDictionary, "RSSI_CTL_AGR")

            NSLog("RSSI: \(rssi)")
        }

        dlclose(libHandle)
    }

这会产生错误fatal error: unexpectedly found nil while unwrapping an Optional value which stems from trying to call _createManager

【问题讨论】:

    标签: ios swift


    【解决方案1】:

    我最终使用了这个解决方法:

    + (int) wifiStrength {
    UIApplication *app = [UIApplication sharedApplication];
    NSArray *subviews = [[[app valueForKey:@"statusBar"] valueForKey:@"foregroundView"] subviews];
    NSString *dataNetworkItemView = nil;
    
    for (id subview in subviews) {
        if([subview isKindOfClass:[NSClassFromString(@"UIStatusBarDataNetworkItemView") class]]) {
            dataNetworkItemView = subview;
            break;
        }
    }
    
    return[[dataNetworkItemView valueForKey:@"wifiStrengthRaw"] intValue];
    }
    

    无需任何权利或越狱即可工作

    【讨论】:

      【解决方案2】:

      由于 iPhone X 的状态栏与其他 iPhone 不同,因此获取 WiFi 信息的方式也不同。

      这里是关于如何通过“undocumented properties”获取它的解决方法,这意味着 Apple 将来可能会在不通知我们的情况下更改这些属性。 如果 Apple 更改了未记录的属性,但我们没有相应地调整我们的代码,应用程序将会崩溃。所以我们必须在 Swift 中处理 NSException。

      创建一个头文件,并将其添加到您的 Bridging-Header.h 中。 你可以找到文件here:https://gist.github.com/zhihuitang/6d3de0963d96a552d47721a598ca79c8

      //
      //  OCCatch.h
      //
      //
      
      #ifndef OCCatch_h
      #define OCCatch_h
      
      // add the code below to your -Bridging-Header.h
      
      /**
       #import "OCCatch.h"
       */
      
      //   How to use it in Swift?
      /**
       let exception = tryBlock {
              let statusBar = UIApplication.shared.value(forKey: "statusBar") as? UIView
              //......
          }
        if let exception = exception {  
          print("exception: \(exception)")
        }  
      */
      
      #import <Foundation/Foundation.h>
      
      NS_INLINE NSException * _Nullable tryBlock(void(^_Nonnull tryBlock)(void)) {
          @try {
              tryBlock();
          }
          @catch (NSException *exception) {
              return exception;
          }
          return nil;
      }
      
      #endif /* OCCatch_h */
      

      在 iPhoneX 中,我们可以得到 WiFi 的 numberOfActiveBars,范围从 0 到 3。 在 iPhoneX 以外的其他 iPhone 上,我们可以获取 WiFi RSSI。

      在iPhoneX上,请使用getWiFiNumberOfActiveBars()

       private func getWiFiNumberOfActiveBars() -> Int? {
          let app = UIApplication.shared
          var numberOfActiveBars: Int?
          let exception = tryBlock {
              guard let containerBar = app.value(forKey: "statusBar") as? UIView else { return nil }
              guard let statusBarMorden = NSClassFromString("UIStatusBar_Modern"), containerBar .isKind(of: statusBarMorden), let statusBar = containerBar.value(forKey: "statusBar") as? UIView else { return nil }
      
              guard let foregroundView = statusBar.value(forKey: "foregroundView") as? UIView else { return nil }
      
              for view in foregroundView.subviews {
                  for v in view.subviews {
                      if let statusBarWifiSignalView = NSClassFromString("_UIStatusBarWifiSignalView"), v .isKind(of: statusBarWifiSignalView) {
                          if let val = v.value(forKey: "numberOfActiveBars") as? Int {
                              numberOfActiveBars = val
                              break
                          }
                      }
                  }
                  if let _ = numberOfActiveBars {
                      break
                  }
              }
          }
          if let exception = exception {
              print("getWiFiNumberOfActiveBars exception: \(exception)")
          }
      
          return numberOfActiveBars
      }
      

      在 iPhoneX 以外的 iPhone 设备上,请使用getWiFiRSSI()

      private func getWiFiRSSI() -> Int? {
          let app = UIApplication.shared
          var rssi: Int?
          let exception = tryBlock {
              guard let statusBar = app.value(forKey: "statusBar") as? UIView else { return }
              if let statusBarMorden = NSClassFromString("UIStatusBar_Modern"), statusBar .isKind(of: statusBarMorden) { return }
      
              guard let foregroundView = statusBar.value(forKey: "foregroundView") as? UIView else { return  }
      
              for view in foregroundView.subviews {
                  if let statusBarDataNetworkItemView = NSClassFromString("UIStatusBarDataNetworkItemView"), view .isKind(of: statusBarDataNetworkItemView) {
                      if let val = view.value(forKey: "wifiStrengthRaw") as? Int {
                          rssi = val
                          break
                      }
                  }
              }
          }
          if let exception = exception {
              print("getWiFiRSSI exception: \(exception)")
          }
          return rssi
      }
      

      到目前为止,我还没有找到在 iPhoneX 上获取 WiFi RSSI 的方法。如果你们知道怎么做,也请告诉我。谢谢。

      这是 Github 中的demo project

      【讨论】:

      • 奇怪的是,像 ARWifiScanner 和 Dr.Wifi 这样的人确实显示了 db 信号值,也在 iPhone X 上,所以它可能的。然而,当直接与 Apple 工程师交谈时,他们说没有办法(显然他们的意思是有记录的方式)但仍然存在。
      • ARSignalMaster 对状态栏进行截图,检测有多少条,然后设置一个 dBm 值和一个围绕它的小随机数生成器。太假了
      • 我对他们的解决方案进行了教育性的反编译,因为我们公司的 Apple 技术人员有一个对话,明确表示他们没有使用热点帮助 API,但不会指定如何完成。跨度>
      • 不编译。您需要在 guard 语句中返回 nil。
      【解决方案3】:

      我认为最新版本的 iOS 是不可能的。最多只能到 iOS4。

      【讨论】:

      • 我设法获得了要构建的代码,但由于需要权利,它似乎无法工作,它应该可以在越狱手机上工作
      • 不,因为您无法获得运行它所需的权利
      【解决方案4】:

      苹果不喜欢这种做法,威胁app review rejection

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2011-10-31
        • 1970-01-01
        • 2015-05-13
        • 1970-01-01
        • 1970-01-01
        • 2016-04-16
        • 2017-05-25
        • 1970-01-01
        相关资源
        最近更新 更多