当接近传感器被覆盖时保持显示屏开启

16

我想在不关闭显示屏的情况下截取近距离传感器。

通过文档,我知道有两个布尔变量:

proximityMonitoringEnabled
proximityState

并且这段代码

[UIDevice currentDevice].proximityMonitoringEnabled = YES;
当接近传感器检测到物体时,它会关闭显示屏,就像在通话时将电话靠近耳朵时一样。如何在接近传感器被遮盖时保持显示屏常亮?

嗨,感谢答复。好的,通过您的代码我可以知道接近传感器的状态,但如果状态是“YES”,那么显示屏仍然不可见吗? - Simone Pistecchia
5个回答

8

在阅读了关于此问题的不同论坛之后,我们得知目前在公共API中无法阻止iPhone接近传感器被遮挡时屏幕变黑。您可以通过通知中心告知传感器是否被遮挡,但是您无法控制其自然行为(即当它使屏幕变暗/黑时)。


有趣的是,Google和PeekCalendar都能够使用这个功能,并且仍然可以通过苹果发布他们的应用程序-请参见http://www.peekcalendar.com/。 - JCutting8

7

苹果的文档指出:“不是所有的iPhone OS设备都有接近传感器。”要确定您的应用程序运行的设备是否支持接近监测,请将proximityMonitoringEnabled属性设置为YES,然后检查其值:

UIDevice *device = [UIDevice currentDevice];
[device setProximityMonitoringEnabled:YES];

if (device.proximityMonitoringEnabled == YES) {
    [[NSNotificationCenter defaultCenter] addObserver:self 
                                             selector:@selector(proximityChanged:) 
                                                 name:@"UIDeviceProximityStateDidChangeNotification"
                                               object:device];
}

- (void) proximityChanged:(NSNotification *)notification {
    UIDevice *device = [notification object];
    NSLog(@"In proximity: %i", device.proximityState);
}

来源:http://www.whatsoniphone.com/blog/new-in-iphone-30-tutorial-series-part-4-proximity-detection/

将帮助检测传感器的当前状态。

公共API允许屏幕变暗:

[UIScreen mainScreen].wantsSoftwareDimming = YES;
[UIScreen mainScreen].brightness = $your_brightness_value;

在这里找到:iOS 6中如何更改wantsSoftwareDimming?


1
嗨,我现在才能回复。当传感器被覆盖时,我可以做些什么,但是显示屏仍然关闭! - Simone Pistecchia
@SimonePistecchia 为什么不把你尝试过的内容更新到问题中,这样我们可以更好地帮助你。 - Unheilig
Simone Pistecchia,编辑了我的答案,介绍如何使用公共API调暗屏幕。 - Vi Matviichuk
问题是如何在仍能使用接近传感器检测接近度的情况下保持屏幕开启。这个答案导致屏幕仍然会关闭。 - JCutting8

6
尽管没有公共API可以完成此操作,但您可以钩入IOKit的IOHIDEventSystem并监听屏幕变暗通知:
// Create and open an event system.
IOHIDEventSystemRef system = IOHIDEventSystemCreate(NULL);

// Set the PrimaryUsagePage and PrimaryUsage that the AppleProxShim service uses
int page = 65280;
int usage = 8;

// Create a dictionary to match the service with
CFStringRef keys[2];
CFNumberRef nums[2];
keys[0] = CFStringCreateWithCString(0, "PrimaryUsagePage", 0);
keys[1] = CFStringCreateWithCString(0, "PrimaryUsage", 0);
nums[0] = CFNumberCreate(0, kCFNumberSInt32Type, &page);
nums[1] = CFNumberCreate(0, kCFNumberSInt32Type, &usage);
CFDictionaryRef dict = CFDictionaryCreate(0, (const void**)keys, (const void**)nums, 2, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
// Get the total of matching services with the above criteria
CFArrayRef srvs = (CFArrayRef)IOHIDEventSystemCopyMatchingServices(system, dict, 0, 0, 0, 0);

// Get the service
IOHIDServiceRef serv = (IOHIDServiceRef)CFArrayGetValueAtIndex(srvs, 0);
int interval = 1 ;

// Set an interval of 1 , to activate the sensor  
IOHIDServiceSetProperty((IOHIDServiceRef)serv, CFSTR("ReportInterval"), CFNumberCreate(0, kCFNumberSInt32Type, &interval));

// add your event handler
IOHIDEventSystemOpen(system, handle_event, NULL, NULL, NULL);
int defaultInterval = 0;
IOHIDServiceSetProperty((IOHIDServiceRef)serv, CFSTR("ReportInterval"), CFNumberCreate(0, kCFNumberSInt32Type, &defaultInterval));

// close handles and release the IOHIDEventSystemRef
IOHIDEventSystemClose(system, NULL);
CFRelease(system);

您的事件处理程序函数指针将类似于这样:
void handle_event(void* target, void* refcon, IOHIDServiceRef service, IOHIDEventRef event) {
    if (IOHIDEventGetType(event) == kIOHIDEventTypeProximity) { // Proximity Event Received
        // not necessary, but if you want the value from the sensor, get it from IOHIDEventGetIntegerValue
        int proximityValue = IOHIDEventGetIntegerValue(event, (IOHIDEventField)kIOHIDEventFieldProximityDetectionMask); // Get the value of the ProximityChanged Field (0 or 64)

        // Call dimScreen with the boolean NO
        int (*SBSSpringBoardServerPort)() = (int (*)())dlsym(RTLD_DEFAULT, "SBSSpringBoardServerPort");
        int port = SBSSpringBoardServerPort(); 
        void (*_SBDimScreen)(int _port,BOOL shouldDim) = (void (*)(int _port,BOOL shouldDim))dlsym(RTLD_DEFAULT, "SBDimScreen");

        // This is where the logic to dim the screen based on the sensor value would go.  In this case, I'm hardcoding NO instead of the value of proximityValue from above
        // BOOL dim = proximityValue == 0 ? NO : YES;
        _SBDimScreen(port, NO); 
    }
}

调用_SBDimScreen可能并不必要,因为空函数指针可以阻止所有接近传感器事件。

代码修改自 iPhoneDevWiki 上的AppleProxShim页面上的命令行工具示例。


非常感谢您提供如此出色的答案!希望在某个时候能够不使用 IOKit 实现。 - Daniel Storm
感谢@DanielStorm,祝你好运!如果这个公共API曝光了,我会更新的。 - JAL
你如何在 Swift 应用程序中实现像这样的 C++ 代码? - JCutting8
@JAL 有没有关于在非Objective-C应用程序中实现私有API使用的好教程? - JCutting8
1
如果你使用这种方法,你的应用程序会被App Store拒绝吗? - JCutting8

0
使用以下API来启用/禁用接近传感器。
[UIDevice currentDevice].proximityMonitoringEnabled = NO; // Disables the Proximity Sensor and won't turnoff the display when sensor covered

[UIDevice currentDevice].proximityMonitoringEnabled = YES; // Enables the Proximity Sensor and will turnoff the display when sensor covered

不是所有的iOS设备都具有接近传感器。要确定是否可用接近监测,请尝试启用它。如果 proximityMonitoringEnabled 属性的值仍然为 NO,则不支持接近监测。

我已经在iOS 9.2.1的iPhone 6上进行了测试。 - Praveen Matanam

0

针对 Swift / iOS 10 / Xcode 8.2

UIDevice.current.isProximityMonitoringEnabled = true/false..

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接