UIApplication​Delegate 的launch​Options

参考文档:
UIApplication​Delegate launch​Options
获取iOS的应用程序打开的方式
启动选项键
应用服务位置更新启动应用程序

launch​Options 用于访问启动选项字典中传递给应用程序的键
application: will Finish Launching With Options:
和应用程序application: did Finish Launching With Options:
应用程序委托的方法。


AppDelegate 是 iOS 各种功能的集散中心。

应用生命周期管理?URL 路由?通知?Core Data 咒语?各种三方 SDK 的初始化?一些似乎放在哪里都不合适的零散功能?统统丢进 AppDelegate.m 里吧!

在 AppDelegate 所有这些拥挤的、超出负载的方法中,-application:didFinishLaunchingWithOptions: 是最臃肿的一个了。

对于很多开发者来说 launchOptions 参数就是类似于 Java 的 main 函数中 String[] args 的作用 —— 在构建应用时候一般是被忽略的。在其平淡的外表下,launchOptions 其实隐藏着 iOS 应用启动时携带的大量核心信息。


每个应用都使用 UIApplicationDelegate -application:didFinishLaunchingWithOptions:(更精确地说以后或许也包含 -application:willFinishLaunchingWithOptions:) 启动。应用调用这个方法来告诉 delegate 进程已经启动完毕,已经准备好运行了。

Springboard 中点击图标应用就开始启动了,但也有其他一些启动的方法。比如说注册了自定义 URL scheme 的应用可以以类似于twitter://的方式从一个 URL 启动。应用可以通过推送通知或地理位置变更启动。

查明应用为什么以及是如何启动的,就是 launchOptions 参数的职责所在。就像 userInfo 字典一样,在-application:didFinishLaunchingWithOptions:的 launchOptions 中也包含很多特别命名的键。

这些键中的许多在应用启动时发出的 UIApplicationDidFinishLaunchingNotification 的通知中也可用,详细内容请查阅文档。

launchOptions 包含的键太多了,按照应用启动原因分组理解起来更容易一点:

一、从URL打开

[[UIApplication sharedApplication] openURL:[NSURL URLWithString:@"app://..."]];

例如:http:// 开头的 URL 会在 Safari 中打开,mailto:// 开头的 URL 会在邮件中打开,tel:// 开头的 URL 会在电话中打开。

这些情况下 UIApplicationLaunchOptionsURLKey 键就会很常用了。

  • UIApplicationLaunchOptionsSourceApplicationKey为调用openurl打开的源程序的bundle id。
  • UIApplicationLaunchOptionsURLKey 为openurl所传的参数,如果app有多个url schema时可以在这里做判断。
//- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions 
launchOptions {
        UIApplicationLaunchOptionsSourceApplicationKey = "com.Juny-RouterDemo";
        UIApplicationLaunchOptionsURLKey = "APPSkip://RedVC";
}

//- (BOOL)application:(UIApplication *)app openURL:(NSURL *)url options:(NSDictionary<UIApplicationOpenURLOptionsKey, id> *)options

options {
         UIApplicationOpenURLOptionsOpenInPlaceKey = 0; 
         UIApplicationOpenURLOptionsSourceApplicationKey = "com.Juny-RouterDemo";
}

应用也可以通过 URL 和附加系统信息打开。当应用从 AirDrop 的 UIDocumentInteractionController 中打开时,launchOptions 会包含下列这键:

  • UIApplicationLaunchOptionsSourceApplicationKey:请求打开应用的应用 id。对应的值是请求打开应用的 bundle ID 的 NSString 对象
  • UIApplicationLaunchOptionsAnnotationKey:标示通过 URL 打开应用时携带了自定义数据。对应的值是包含自定义数据的属性列表对象
NSURL *fileURL = [[NSBundle mainBundle] URLForResource:@"Document" withExtension:@"pdf"];
if (fileURL) {
    UIDocumentInteractionController *documentInteractionController = [UIDocumentInteractionController interactionControllerWithURL:fileURL];
    documentInteractionController.annotation = @{@"foo": @"bar"};
    [documentInteractionController setDelegate:self];
    [documentInteractionController presentPreviewAnimated:YES];
}

二、响应通知

不要和 NSNotification
混淆了,应用可以通过本地(local)或远程(remote)通知打开。

应用可以制定计划在未来某个时间点触发 UILocalNotification。如果应用处于打开状态,那么将回调-application:didReceiveLocalNotification:方法。如果应用处于非活跃状态,通知将会被发送到通知中心。

不像推送通知,UIApplication 的 delegate 提供了统一控制本地通知的方法。如果应用是通过本地通知启动的,-application:didReceiveLocalNotification:将会在-application:didFinishLaunchingWithOptions:之后被自动调用(意思就是不需要像推送通知一样在 -application:didFinishLaunchingWithOptions:` 中手动调用了)。

本地通知会在启动参数中携带和推送通知有类似结构的 UIApplicationLaunchOptionsLocalNotificationKey:

  • UIApplicationLaunchOptionsLocalNotificationKey: 标示本地通知目前处于可用状态。对应的值是包含通知内容的 NSDictionary。
//远程推送UIApplicationLaunchOptionsRemoteNotificationKey 直接是一个推送的JSON内容。
launchOptions {
    UIApplicationLaunchOptionsRemoteNotificationKey =     {
         aps =         {
                alert = test;
                badge = 1;
                sound = default;
             };
        };
     }

 //通过本地推送(localnotification)打开.UIApplicationLaunchOptionsLocationNotificationKey为本地推送的内容。
launchOptions {
         UIApplicationLaunchOptionsLocationNotificationKey = "<UIConcreteLocalNotification: 0x1e5c8b60>{fire date = 2017\U5e749\U67089\U65e5\U661f\U671f\U4e00 \U4e2d\U56fd\U6807\U51c6\U65f6\U95f411\U65f613\U520655\U79d2, time zone = Asia/Shanghai (GMT+0800) offset 28800, repeat interval = 0, repeat count = UILocalNotificationInfiniteRepeatCount, next fire date = (null), user info = {\n}}";
     }

三、地理位置事件

iOS的位置监控,可以让我们的应用通过地理位置触发事件的启动

UIApplicationLaunchOptionsLocationKey:该键的存在表示应用程序是响应于传入位置事件而启动的。该键的值是包含NSNumber 布尔值的对象。您应该使用此键的存在作为信号来创建对象并重新启动位置服务。位置数据仅传递给位置管理器委托,而不使用该键。CLLocationManager

我们需要一直跟踪用户位置(但又不想耗尽电池)。我们能在程序被杀死后获取位置更新的唯一方法是使用startMonitoringSignificantLocationChanges

**startMonitoringSignificantLocationChanges**如果您启动此服务,并且应用程序随后终止,则如果新事件到达,系统将自动重新启动应用程序到后台。在这种情况下,将选项字典传递给应用程序:didFinishLaunchingWithOptions:应用程序委托方法包含UIApplicationLaunchOptionsLocationKey键,表示您的应用程序是由于位置事件而启动的。重新启动后,您仍然必须配置位置管理器对象并调用此方法来继续接收位置事件。当您重新启动位置服务时,当前事件将立即发送给您的代表。此外,即使在启动位置服务之前,您的位置管理器对象的位置属性也会填充最新的位置对象。

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    // Override point for customization after application launch.
    
    if (![CLLocationManager locationServicesEnabled]) {
        [[[UIAlertView alloc] initWithTitle:NSLocalizedString(@"Location Services Disabled", nil)
                                    message:NSLocalizedString(@"You currently have all location services for this device disabled. If you proceed, you will be asked to confirm whether location services should be reenabled.", nil)
                                   delegate:nil
                          cancelButtonTitle:NSLocalizedString(@"OK", nil)
                          otherButtonTitles:nil] show];
    } else {
        self.locationManager = [[CLLocationManager alloc] init];
        self.locationManager.delegate = self;
        //
        [self.locationManager startMonitoringSignificantLocationChanges];
    }
    
    if (launchOptions[UIApplicationLaunchOptionsLocationKey]) {
        [self.locationManager startUpdatingLocation];
    }
    
    
     return YES;
}

//////位置改变的代理
- (void)locationManager:(CLLocationManager *)manager 
    didUpdateToLocation:(CLLocation *)newLocation 
           fromLocation:(CLLocation *)oldLocation {

    if ( abs([newLocation.timestamp timeIntervalSinceDate: [NSDate date]]) < 30) {
        self.lastLocation = newLocation;
        [self updateLocation]; //sending location to server

}

三、报刊杂志(Newsstand)

当有新的可用下载时,报刊杂志应用可以启动。

这样注册即可:

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    // Override point for customization after application launch.

    [application registerForRemoteNotifications];
    
     return YES;
}

然后在启动项里面找这个键:

UIApplicationLaunchOptionsNewsstandDownloadsKey:标示应用有新的可用杂志资源下载。对应的值是包含 NKAssetDownload id 的字符串数组。虽然你可以通过这些 id 进行检查,但还是应该通过 NKLibrary 对象的 downloadingAssets 属性来持有这些 NKAssetDownload 对象(可用用于展示下载进度或错误)以便显示在报刊杂志书架中。

四、蓝牙

iOS7开始支持外围蓝牙设备重新唤醒应用。

应用启动后通过特定的id实例化一个CBCentralManager或CBPeripheralManager用于连接蓝牙设备,之后 应用就可以通过蓝牙系统的相关动作来重新唤醒了。取决于发出通知的是一个中心设备还是外围设备,launchOptions会传入一下两个键中的一个:

UIApplicationLaunchOptionsBluetoothCentralsKey:标示应用之前曾有过一个或多个CBCentralManager对象并被蓝牙系统的相关动作唤醒过。对应的值是包含NSString对象的数组。数组中每一个字符串表示一个中心设备的恢复连接id。
标示应用之前曾有过一个或多个 CBPeripheralManager 对象并被蓝牙系统的相关动作唤醒过。对应的值是包含 NSString 对象的数组。数组中每一个字符串表示一个外围设备的恢复连接 id。

// .h
@import CoreBluetooth;

@interface AppDelegate () <CBCentralManagerDelegate>
@property (readwrite, nonatomic, strong) CBCentralManager *centralManager;
@end

// .m
self.centralManager = [[CBCentralManager alloc] initWithDelegate:self queue:nil options:@{CBCentralManagerOptionRestoreIdentifierKey:(launchOptions[UIApplicationLaunchOptionsBluetoothCentralsKey] ?: [[NSUUID UUID] UUIDString])}];

if (self.centralManager.state == CBCentralManagerStatePoweredOn) {
    static NSString * const UID = @"7C13BAA0-A5D4-4624-9397-15BF67161B1C"; // generated with `$ uuidgen`
    NSArray *services = @[[CBUUID UUIDWithString:UID]];
    NSDictionary *scanOptions = @{CBCentralManagerScanOptionAllowDuplicatesKey:@YES};
    [self.centralManager scanForPeripheralsWithServices:services options:scanOptions];
}

要搞清楚所有的启动参数确实要费点力气。幸运的是一般的应用只需要处理其中的一两种就够了。了解所有的可能性需要从理解概念走到亲自实现的步骤上。当你了解到事情有那么多可能性的时候,下一个改变世界的想法可能就已经在脑中开始酝酿了。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,362评论 5 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,330评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,247评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,560评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,580评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,569评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,929评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,587评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,840评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,596评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,678评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,366评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,945评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,929评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,165评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,271评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,403评论 2 342

推荐阅读更多精彩内容