锁屏和解锁的时间机制

idleTimer

idleTimer 是iOS内置的时间监测机制,当在一段时间内未操作即进入锁屏状态。但有些应用程序是不需要锁住屏幕的,比如游戏,视频这类应用。 可以通过设置UIApplication的idleTimerDisabled属性来指定iOS是否锁屏。

// 禁用休闲时钟 
[[UIApplication sharedApplication] setIdleTimerDisabled: YES]; 

也可以使用这种语法

[UIApplication sharedApplication].idleTimerDisabled = YES;

但是,这个命令只能禁用自动锁屏,如果点击了锁屏按钮,仍然会进入锁屏的。有一点例外的是,AVPlayer不用设置idleTimerDisabled=YES,也能屏幕常亮,播放完成后过一分钟就自动关闭屏幕。有兴趣的可以自己尝试一下。

锁屏和解锁通知

iPhone的锁屏监测分为两种方式监听:一种是程序在前台,另一种程序在后台。 程序在前台,这种比较简单。直接使用Darwin层的通知就可以了:

Darwin是由苹果电脑于2000年所释出的一个开放原始码操作系统。Darwin 是MacOSX 操作环境的操作系统成份。苹果电脑于2000年把Darwin 释出给开放原始码社群。现在的Darwin皆可以在苹果电脑的PowerPC 架构和X86 架构下执行,而后者的架构只有有限的驱动程序支援。

#import <notify.h>
#define NotificationLock CFSTR("com.apple.springboard.lockcomplete")
#define NotificationChange CFSTR("com.apple.springboard.lockstate")
#define NotificationPwdUI CFSTR("com.apple.springboard.hasBlankedScreen")

static void screenLockStateChanged(CFNotificationCenterRef center,void* observer,CFStringRef name,const void* object,CFDictionaryRef userInfo)
{
NSString* lockstate = (__bridge NSString*)name;
if ([lockstate isEqualToString:(__bridge  NSString*)NotificationLock]) {
    NSLog(@"locked.");
} else {
    NSLog(@"lock state changed.");
}
}

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
CFNotificationCenterAddObserver(CFNotificationCenterGetDarwinNotifyCenter(), NULL, screenLockStateChanged, NotificationLock, NULL, CFNotificationSuspensionBehaviorDeliverImmediately);
CFNotificationCenterAddObserver(CFNotificationCenterGetDarwinNotifyCenter(), NULL, screenLockStateChanged, NotificationChange, NULL, CFNotificationSuspensionBehaviorDeliverImmediately);
return YES;
}

notify.h的具体内容可以移步开发文档。这种方法,程序在前台是可以拿到的,在后台情况下就无能为力了。

第二种是程序退后台后,这时再锁屏就收不到上面的那个通知了,需要另外一种方式, 以循环的方式一直来检测是否是锁屏状态,会消耗性能并可能被苹果挂起,需要合理设置循环时间。

static void setScreenStateCb()
{
uint64_t locked;

__block int token = 0;
notify_register_dispatch("com.apple.springboard.lockstate",&token,dispatch_get_main_queue(),^(int t){
});
notify_get_state(token, &locked);
NSLog(@"%d",(int)locked);
}

- (void)applicationDidEnterBackground:(UIApplication *)application
{
while (YES) {
    setScreenStateCb();
    sleep(5); // 循环5s
}
}

UIApplication

上面我们使用了UIApplication的IdleTimerDisabled方法,下面就大概了解下UIApplication吧。

UIApplication,每个程序只能有一个,系统使用的是单例模式,用[UIApplication sharedApplication]来得到一个实例。这个单例实例是在系统启动时由main函数里面的UIApplicationMain方法生成,实现的是UIApplicationDelegate的Protocol,也就是AppDelegate的一个实例。每次通过[UIApplication sharedApplication]调用的就是它。UIApplication保存一个UIWindow对象序列,用来快速恢复views。

UIApplication在程序里的作用很多,大致如下所示:

一、远程提醒,就是push notification注册;
二、可以连接到UIUndoManager;在Cocoa中使用NSUndoManager可以很方便的完成撤销操作。NSUndoManager会记录下修改、撤销操作的消息。这个机制使用两个NSInvocation对象栈。当进行操作时,控制器会添加一个该操作的逆操作的invocation到Undo栈中。当进行Undo操作时,Undo操作的逆操作会倍添加到Redo栈中,就这样利用Undo和Redo两个堆栈巧妙的实现撤销操作。需要注意的是,堆栈中存放的都是NSInvocation实例。
三、检查能否打开某个URL,并且打开URL;这个功能可以配合应用的自定义URL功能,来检测是否安装了某个应用。使用的是[[UIApplication sharedApplication] canOpenURL:url]方法。如果返回YES,可执行[[UIApplication sharedApplication] openURL:url]; 
四、注册Local Notification;
五、在后台运行以及从后台转为前台时的操作;
六、防止屏幕睡眠:即上面的[[UIApplication sharedApplication] setIdleTimerDisabled: YES]; 
七、手动调整status bar的位置和状态,如设置为竖屏、横屏等;
八、设置badge number,就是图标右上角的数字;
九、每当应用联网时,在状态栏上会显示联网小菊花。UIApplication可以设置是否出现。
UIApplication *app = [UIApplication sharedApplication]; 
app.networkActivityIndicatorVisible =!app.networkActivityIndicatorVisible;//转动 
app.networkActivityIndicatorVisible = app.networkActivityIndicatorVisible;//不转动

UIUndoManager示例

- (void) one
{
position = position + 10;
[[undoManager prepareWithInvocationTarget:self] two];
[self showTheChangesToThePostion];
}

- (void) two
{
position = position - 10;
[[undoManager prepareWithInvocationTarget:self] one];
[self showTheChangesToThePostion];
}

prepareWithInvocationTarget:方法记录了target并返回UndoManager,然后UndoManager重载了forwardInvocation方法,也就将two方法的Invocation添加到undo栈中了。

解锁