参考文档:
UIApplicationDelegate launchOptions
获取iOS的应用程序打开的方式
启动选项键
应用服务位置更新启动应用程序
launchOptions 用于访问启动选项字典中传递给应用程序的键
application: will Finish Launching With Options:
和应用程序application: did Finish Launching With Options:
应用程序委托的方法。
UIApplication Launch Options URLKey
此键的存在表示该应用程序已启动,以便打开一个URL。 该键的值是包含要打开的URL的NSURL
对象。UIApplication Launch Options Source Application Key
此键的存在标识了请求启动您的应用程序的应用程序。 该键的值是一个NSString
对象,表示发出请求的应用程序的包ID。UIApplication Launch Options Remote Notification Key
该键的存在表示可以使应用程序进行远程通知。 该键的值是包含NSDictionary
通知的有效载荷的NSDictionary。 请参阅应用程序的application: did Receive Remote Notification:
有关处理远程通知的更多信息。UIApplication Launch Options Annotation Key
此键的存在表示自定义数据是由请求打开URL的应用程序提供的。 该键的值是包含自定义数据的属性列表对象。 相同的对象也被传递给应用程序的application: open URL: source Application: annotation:
方法。 此属性列表对象的内容特定于发出请求的应用程序。UIApplication Launch Options Location Key
该键的存在表示应用程序是响应于传入位置事件而启动的。该键的值是包含NSNumber
布尔值的对象。您应该使用此键的存在作为信号来创建对象并重新启动位置服务。位置数据仅传递给位置管理器委托,而不使用该键。CLLocationManager
UIApplication Launch Options Newsstand Downloads Key
此键的存在表明新下载的报亭资产可用于您的应用程序。 该键的值是一组字符串标识符,用于标识与资产相对应的NKAsset Download对象。 虽然您可以使用标识符进行交叉检查,但您应该通过代表报亭应用程序库的NKLibrary对象的downloading Assets
属性来获取NKAsset Download对象的最终数组(表示正在进行或错误的资产NKAsset Download
)。UIApplication Launch Options Bluetooth Centrals Key
此键的存在表明应用程序以前具有一个或多个CBCentral Manager
对象,并由蓝牙系统重新启动,以继续与这些对象相关联的操作。 该键的值是包含一个或多个NSString
对象的NSArray
对象。UIApplication Launch Options Bluetooth Peripherals Key
该键的存在表明应用程序以前具有一个或多个CBPeripheral Manager
对象,并由蓝牙系统重新启动,以继续与这些对象相关联的操作。 该键的值是包含一个或多个NSString
对象的NSArray
对象。UIApplication Launch Options Shortcut Item Key
包含UIApplication Shortcut Item
对象,表示用户选择启动或激活您的应用程序的主屏幕快速操作。UIApplication Launch Options User Activity Dictionary Key
此键的存在表示该应用程序已启动,以便继续进行用户活动。该键的值是包含键UIApplication Launch Options User Activity Type Key
的NSDictionary
对象,其值是标识活动类型的NSString
对象。UIApplication Launch Options User Activity Type Key
该键用于子字典,它是UIApplication Launch Options Shortcut Item Key
的值。 该键的值是标识活动类型的NSString
对象。
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];
}
要搞清楚所有的启动参数确实要费点力气。幸运的是一般的应用只需要处理其中的一两种就够了。了解所有的可能性需要从理解概念走到亲自实现的步骤上。当你了解到事情有那么多可能性的时候,下一个改变世界的想法可能就已经在脑中开始酝酿了。