Objective-C的UIApplication学习笔记

UIApplication -- 应用程序的集中控制和协调点

iOS中运行的应用程序的集中控制和协调点,每个iOS应用程序都只有一个 UIApplication 的实例 (少部分是 UIApplication 的子类),启动应用时,系统调用 UIApplicationMain 函数。在其他任务中,此函数创建一个 Singleton UIApplication 对象(单例),在此之后可以通过 sharedApplication 类方法调用访问。

application 对象的主要作用是处理初始化传入的用户事件进程。它调度由控制对象 (UIControl 的实例) 转发给它的动作消息(action message) 到适当的目标对象,application 对象维护一个打开的窗口列表 (UIWindow 对象),通过这些可以检索任何应用程序的 UIView 对象。

UIApplication 类定义了一个一个 delegate,这个 delegate 遵循 UIApplicationDelegate 协议,并且必须实现一些协议的方法。application 对象向 delegate 通知重要的 runtime 事件 --- 例如应用程序的启动,低内存警告和应用程序终止等,使其有机会进行适当的响应

这个类中的一些 API 允许程序员对设备进行特殊的行为操作. 使用 UIApplication 的对象执行以下操作 :

  • 暂停传入触摸事件 (beginlgnoringInteractionEvents)
  • 注册远程通知 (unregisterForRemoteNotifications)
  • 触发撤销重做 (undo-redo) UI (applicationSupportsShakeToEdit)
  • 确定是否有已安装的 app 注册处理 URL scheme (canOpenURL:)
  • 拓展应用程序的执行,使其可以在后台完成任务 (beginBackgroundTaskWithExpirationHandler: , beginBackgroundTaskWithName: expirationHandler:)
  • 安排和取消本地通知 (scheduleLocalNotification: , cancelLocalNotification:)
  • 协调遥控事件的接收 (beginReceivingRemoteControlEvents , endReceivingRemoteControlEvents)
  • 执行应用级状态恢复任务
UIApplication常用属性
@property(class, nonatomic, readonly) UIApplication *sharedApplication NS_EXTENSION_UNAVAILABLE_IOS("Use view controller based solutions where appropriate instead.");

属性描述返回单例应用程序实例。UIApplicationMain函数在启动时创建共享应用程序实例。

@property(nullable, nonatomic,readonly) UIWindow *keyWindow API_DEPRECATED("Should not be used for applications that support multiple scenes as it returns a key window across all connected scenes", ios(2.0, 13.0));

属性描述应用程序的主窗口,这个属性在最近发送的makeKeyAndVisible消息的窗口数组中保存UIWindow对象。不应该用于支持多个场景的应用程序,因为它会在所有连接的场景中返回一个主窗口。

\color{red}{获取主窗口: }

UIApplication.sharedApplication.keyWindow
@property(nonatomic) NSInteger applicationIconBadgeNumber; 

属性描述设置应用程序图标右上角的红色提醒数字。设置为0(零)隐藏提醒数字。此属性的默认值为0。

注:设置图标需要引入#import <UserNotifications/UserNotifications.h>给用户发通知。

\color{red}{例如 : 设置应用程序图标右上角的红色提醒数字 }

- (void)viewDidLoad {
    
    [super viewDidLoad];
    self.navigationItem.title = @"测试代码控制器";
    
    UIButton *testCodeButton = [UIButton buttonWithType:UIButtonTypeCustom];
    testCodeButton.frame = CGRectMake(CGRectGetMaxX(self.view.frame) / 2 - 75 / 2, CGRectGetMaxY(self.view.frame) / 2 - 30 / 2, 75, 30);
    testCodeButton.backgroundColor = [UIColor blueColor];
    testCodeButton.titleLabel.font = [UIFont systemFontOfSize:15];
    [testCodeButton setTitle:@"测试代码" forState:UIControlStateNormal];
    [testCodeButton setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];
    [testCodeButton addTarget:self action:@selector(setAppUpperRightCornerNumber) forControlEvents:UIControlEventTouchUpInside];
        [self.view addSubview:testCodeButton];

}

///设置应用程序图标右上角的红色提醒数字
- (void)setAppUpperRightCornerNumber{
    
    UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter];
    [center requestAuthorizationWithOptions:UNAuthorizationOptionBadge completionHandler:^(BOOL granted, NSError * _Nullable error) {
        if (granted) {
            NSLog(@"授权成功!!");
        }
    }];
    [UIApplication sharedApplication].applicationIconBadgeNumber = 10;
}

点击按钮前:

Jietu20200307-152858.gif

点击按钮后 :

Jietu20200307-153337.gif
@property(nonatomic,readonly) CGRect statusBarFrame API_UNAVAILABLE(tvos) API_DEPRECATED("Use the statusBarManager property of the window scene instead.", ios(2.0, 13.0));

属性描述状态栏区域的框架矩形。如果状态栏隐藏,则此属性的值为CGRectZero。

\color{red}{例如获取状态栏的Frame: }

//获取状态栏的Frame
CGRect statusRect = [[UIApplication sharedApplication] statusBarFrame];
@property(nonatomic,getter=isNetworkActivityIndicatorVisible) BOOL networkActivityIndicatorVisible API_UNAVAILABLE(tvos) API_DEPRECATED("Provide a custom network activity UI in your app if desired.", ios(2.0, 13.0));

属性描述打开或关闭网络活动指示器的布尔值。如果应用程序应显示网络活动,请指定“YES”;如果不应显示网络活动,请指定“NO”。默认值为“NO”。状态栏中的旋转指示器显示网络活动。应用程序可能会显式隐藏或显示此指示器。

就是这个,在IphoneX上还不知道给放哪去了:

截屏2020-03-07下午3.55.51.png
typedef NSUInteger UIBackgroundTaskIdentifier NS_TYPED_ENUM;

属性描述 :用于标识要在后台运行的请求的唯一令牌。

UIApplication常用函数
- (BOOL)canOpenURL:(NSURL *)url API_AVAILABLE(ios(3.0));

函数描述返回一个布尔值,指示应用程序是否可用来处理URL方案。当该方法返回YES时,iOS保证后续对openURL:options:completionHandler:方法的调用将成功启动一个能够处理该URL的应用程序。返回值并不表示URL的有效性,也不表示指定的资源是否存在,或者,对于一个通用链接,是否注册了一个已安装的应用程序来响应通用链接。

如果你的应用程序在iOS 9.0或之后被链接,你必须声明你传递给这个方法的URL方案,方法是在你的应用程序的Info.plist文件中添加LSApplicationQueriesSchemes键。对于未声明的方案,此方法总是返回NO,无论是否安装了适当的应用程序。

如果你的应用程序链接到较早版本的iOS,但运行在iOS 9.0或更高版本,你可以调用这个方法多达50次。达到这个限制后,后续调用总是返回NO。如果用户重新安装或升级应用程序,iOS会重置限制。

与此方法不同,openURL:options:completionHandler:方法不受LSApplicationQueriesSchemes要求的约束。如果有一个应用程序可以处理这个URL,系统将启动它,不管你是否声明了这个方案。

使用通用链接而不是自定义URL方案,消除了使用此方法验证目标链接的需要,如果没有可用的应用程序来处理通用链接,iOS会将其路由到Safari,允许相关网站进行响应。

参数 :

url : 一个URL(通用资源定位器)。在运行时,系统确定是否注册了已安装的应用程序来处理URL的方案。可以注册多个应用程序来处理一个方案。
URL可以有一个通用的模式,比如http、https、tel或facetime,或者自定义模式。

返回值 : 如果设备上安装的应用程序未注册以处理该URL的方案,或者您尚未在Info.plist文件中声明该URL的方案,则为NO;否则为YES。

- (void)openURL:(NSURL*)url options:(NSDictionary<UIApplicationOpenExternalURLOptionsKey, id> *)options completionHandler:(void (^ __nullable)(BOOL success))completion API_AVAILABLE(ios(10.0)) NS_EXTENSION_UNAVAILABLE_IOS("");

函数描述尝试异步打开指定URL处的资源。使用此方法打开指定的资源。如果指定的URL模式由另一个应用程序处理,iOS将启动该应用程序并将URL传递给它(启动应用程序会把另一个应用程序带到前台)。如果没有应用程序能够处理指定的方案,则调用完成处理程序,并将success参数设置为NO。要确定是否安装了能够处理URL的应用程序,请在调用此应用程序之前调用canOpenURL:方法。

参数 :

url : 一个URL(通用资源定位器)。此URL标识的资源可能是当前应用程序的本地资源,也可能是必须由其他应用程序提供的资源。UIKit支持许多常见的方案,包括http、https、tel、facetime和mailto方案。还可以使用与设备上安装的应用程序关联的自定义URL方案。

options : 打开URL时要使用的选项字典。

completionHandler : 要与结果一起执行的块。如果要通知您打开URL的成功或失败,请为此参数提供一个值。此块在应用程序的主线程上异步执行。块没有返回值,并接受以下参数:

  • success : 指示是否成功打开URL的布尔值。
UIKIT_EXTERN UIApplicationOpenURLOptionsKey const UIApplicationOpenURLOptionsSourceApplicationKey NS_SWIFT_NAME(sourceApplication) API_AVAILABLE(ios(9.0));  

注 :打开URL时要使用的选项字典

选项描述 : 包含向应用程序发送打开URL请求的应用程序的捆绑包ID的密钥。这个键的值是一个NSString对象,包含发出请求的应用程序的bundle ID。如果请求来自属于您的团队的另一个应用程序,则UIKit会将此密钥的值设置为该应用程序的ID。如果发起应用程序的团队标识符不同于当前应用程序的团队标识符,则密钥的值为nil。

\color{red}{例如拨打电话 : }

NSString *tel = [NSString stringWithFormat:@"telprompt://%@", self.phone];
NSURL *url = [NSURL URLWithString:tel];
if ([[UIApplication sharedApplication] canOpenURL:url]) {
    [[UIApplication sharedApplication] openURL:url options:@{UIApplicationOpenURLOptionsSourceApplicationKey:@YES} completionHandler:nil];
}
- (UIBackgroundTaskIdentifier)beginBackgroundTaskWithExpirationHandler:(void(^ __nullable)(void))handler  API_AVAILABLE(ios(4.0)) NS_REQUIRES_SUPER;

函数描述标记新的长时间运行的后台任务的开始

这个方法为应用程序请求额外的后台执行时间。在任务未完成时调用此方法可能会损害应用程序的用户体验。例如,在将数据写入文件之前调用此方法,以防止系统在操作过程中挂起应用程序。不要简单地使用此方法在应用移动到后台后使其保持运行。

在开始任务之前,尽可能早地调用这个方法,最好是在应用程序实际进入后台之前。该方法异步地请求应用程序的任务断言。如果在应用程序挂起前不久调用此方法,则系统可能会在授予任务断言之前挂起应用程序。例如,不要在applicationDidEnterBackground:方法结束时调用此方法,并期望应用程序继续运行。如果系统无法授予任务断言,它将调用过期处理程序。

对该方法的每个调用都必须由对endBackgroundTask:method的匹配调用进行平衡。运行后台任务的应用程序运行它们的时间是有限的。(可以使用backgroundTimeRemaining属性找出有多少时间可用。)如果不调用endBackgroundTask:对于时间到期之前的每个任务,系统将终止应用程序。如果在handler参数中提供一个block对象,则系统会在时间到期之前调用处理程序,以便有机会结束任务。

可以在应用程序执行的任何时候调用此方法。您也可以多次调用此方法来标记并行运行的多个后台任务的开始。但是,每个任务都必须单独结束。使用此方法返回的值标识给定任务。

为了帮助调试,此方法根据调用方法或函数的名称为任务生成一个名称。如果要指定自定义名称,请改用beginBackgroundTaskWithName:expirationHandler:方法。
可以在非主线程上安全地调用此方法。若要延长应用程序扩展的执行时间,请改用NSProcessInfo的performExpiringActivityWithReason:usingBlock:方法。

使用BGProcessingTask执行需要更长时间的任意后台处理任务。

如果调试后台任务代码时遇到问题,可以尝试使用beginBackgroundTaskWithName:expirationHandler:方法而不是此方法。该方法提供与此方法相同的行为,但允许您为任务指定调试器可见名称。

参数 :

handler : 在应用程序的剩余后台时间到达0之前不久要调用的处理程序。使用此处理程序清理并标记后台任务的结束。未能明确结束任务将导致应用程序终止。系统在主线程上同步调用处理程序,暂时阻止应用程序的挂起。

返回值 : 新后台任务的唯一标识符。必须将此值传递给endBackgroundTask:方法以标记此任务的结束。如果无法在后台运行,则此方法返回UIBackgroundTaskInvalid。

UIApplication (UIRemoteControlEvents) -- 远程控制事件
- (void)beginReceivingRemoteControlEvents API_AVAILABLE(ios(4.0));

函数描述 :通知应用程序开始接收远程控制事件。在iOS 7.1及更高版本中,使用共享的MPRemoteCommandCenter对象注册远程控制事件。使用共享命令中心对象时,不需要调用此方法。此方法使用响应器链开始远程控制事件的传递。远程控制事件源于耳机和外部附件发出的命令,旨在控制应用程序呈现的多媒体。要停止接收远程控制事件,必须调用endReceivingRemoteControlEvents。

\color{red}{例如播放器添加远程控制处理程序的代码片段: }

/// 添加远程控制处理程序
- (void)addRemoteControlHandler{
    if (@available (iOS 7.1, *)) {
        //应用程序开始接收远程控制事件
        [[UIApplication sharedApplication] beginReceivingRemoteControlEvents];
        //在iOS 7.1及更高版本中,使用共享的MPRemoteCommandCenter对象注册远程控制事件
        MPRemoteCommandCenter *center = [MPRemoteCommandCenter sharedCommandCenter];
        //添加开始播放命令连接的函数
        [self addRemoteCommand:center.playCommand selector:@selector(hy_play)];
        //添加暂停播放命令连接的函数
        [self addRemoteCommand:center.pauseCommand selector:@selector(hy_pause)];
        //添加选择上一曲目命令连接的函数
        [self addRemoteCommand:center.previousTrackCommand selector:@selector(hy_last)];
        //添加选择下一曲目命令连接的函数
        [self addRemoteCommand:center.nextTrackCommand selector:@selector(hy_next)];
        //添加切换播放和暂停时执行的回调函数
        [center.togglePlayPauseCommand addTargetWithHandler:^MPRemoteCommandHandlerStatus(MPRemoteCommandEvent * _Nonnull event) {
            if ([HYAudioFrequencyPlayer sharedPlayer].state == HYPlayerStatePlaying) {
                [[HYAudioFrequencyPlayer sharedPlayer] hy_pause];
            }else{
                [[HYAudioFrequencyPlayer sharedPlayer] hy_play];
            }
            return MPRemoteCommandHandlerStatusSuccess;
        }];
        //在iOS 9.1及更高版本中
        if (@available (iOS 9.1,*)) {
            //添加跳转播放位置执行的回调函数
            [center.changePlaybackPositionCommand addTargetWithHandler:^MPRemoteCommandHandlerStatus(MPRemoteCommandEvent * _Nonnull event) {
                MPChangePlaybackPositionCommandEvent *positionEvent = (MPChangePlaybackPositionCommandEvent *)event;
                //避免出现inf
                if (self.totalTime > 0) {
                    //音频播放时间跳转
                    [self hy_seekToTime:positionEvent.positionTime / self.totalTime completionBlock:nil];
                }
                return MPRemoteCommandHandlerStatusSuccess;
            }];
        }
    }
}

/// 添加远程命令链接的函数
/// - Parameters:
///   - command: 远程命令
///   - selector: 链接的函数
- (void)addRemoteCommand:(MPRemoteCommand *)command selector:(SEL)selector{
    [command addTargetWithHandler:^MPRemoteCommandHandlerStatus(MPRemoteCommandEvent * _Nonnull event) {
        if ([self respondsToSelector:selector]) {
            IMP imp = [self methodForSelector:selector];
            void (*func)(id, SEL) = (void *)imp;
            func(self, selector);
        }
        return MPRemoteCommandHandlerStatusSuccess;
    }];
}
- (void)endReceivingRemoteControlEvents API_AVAILABLE(ios(4.0));

函数描述 :通知应用程序结束接收远程控制事件。在iOS 7.1及更高版本中,使用共享的MPRemoteCommandCenter对象注销远程控制事件。使用共享命令中心对象时,不需要调用此方法。此方法停止使用响应器链传递远程控制事件。远程控制事件源于耳机和外部附件发出的命令,旨在控制应用程序呈现的多媒体。

\color{red}{例如播放器移除远程控制处理程序的代码片段: }

if (@available(iOS 7.1, *)) {
        //应用程序停止接收远程控制事件
        [[UIApplication sharedApplication] endReceivingRemoteControlEvents];
        //在iOS 7.1及更高版本中,使用共享的MPRemoteCommandCenter对象移除远程控制事件
        MPRemoteCommandCenter *center = [MPRemoteCommandCenter sharedCommandCenter];
        //移除开始播放命令连接的函数
        [[center playCommand] removeTarget:self];
        //移除暂停播放命令连接的函数
        [[center pauseCommand] removeTarget:self];
        //移除选择下一曲目命令连接的函数
        [[center nextTrackCommand] removeTarget:self];
        //移除选择上一曲目命令连接的函数
        [[center previousTrackCommand] removeTarget:self];
        //移除切换播放和暂停时执行的回调函数
        [[center togglePlayPauseCommand] removeTarget:self];
        //移除跳转播放位置执行的回调函数
        if(@available(iOS 9.1, *)) {
            [center.changePlaybackPositionCommand removeTarget:self];
        }
    }

在锁屏时,在小组件中传递的播放器操作事件就需要注册远程控制事件:

截屏2023-01-28 17.37.38.png
UIApplicationDelegate -- 应用程序代理
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(nullable NSDictionary<UIApplicationLaunchOptionsKey, id> *)launchOptions API_AVAILABLE(ios(3.0));

函数描述通知代理启动过程即将完成,应用程序即将运行

使用此方法(以及相应的application:willFinishLaunchingWithOptions:方法)完成应用程序的初始化并进行最后的调整。此方法在状态恢复发生后调用,但在应用程序的窗口和其他UI显示之前调用。在该方法返回后的某个时间点,系统调用应用委托的另一个方法以将应用移动到活动(前台)状态或后台状态。

如果没有实现application:willFinishLaunchingWithOptions:方法,此方法表示您最后一次处理launchOptions字典中的任何键。应在此方法中查看它们并提供适当的响应。非app委托的对象可以通过观察名为UIApplicationDidFinishLaunchingNotification的通知并访问该通知的userInfo字典来访问相同的launchOptions字典值。该通知将在此方法返回后不久发送。

对于应用程序初始化,强烈建议您使用此方法和application:willFinishLaunchingWithOptions:方法,而不要使用applicationDidFinishLaunching:方法,该方法仅适用于在较旧版本的iOS上运行的应用程序。

此方法的返回结果与application:willFinishLaunchingWithOptions:方法的返回结果相结合,以确定是否应处理URL。如果任一方法返回NO,则不处理URL。如果不实现其中一个方法,则只考虑实现方法的返回值。

参数 :

application : 单例应用程序对象。

launchOptions : 说明应用程序启动原因的字典(如果有的话)。在用户直接启动应用程序的情况下,本词典的内容可能是空的。

返回值 : 如果应用程序无法处理URL资源或继续用户活动,则返回“NO”,否则返回“YES”。如果应用程序是作为远程通知的结果启动的,则忽略返回值。

- (void)applicationWillResignActive:(UIApplication *)application;

函数描述通知代理应用程序即将变为非活动状态

调用此方法是为了让应用程序知道它将从活动状态移动到非活动状态。这可能发生在某些类型的临时中断(如来电或短信息)或当用户退出应用程序并开始转换到后台状态时。处于非活动状态的应用程序将继续运行,但不会将传入事件分派给响应程序。

应该使用此方法暂停正在进行的任务,禁用计时器,并限制OpenGL ES帧速率。游戏应该使用这种方法来暂停游戏。处于非活动状态的应用程序在等待转换到活动状态或后台状态时应完成最少的工作。

如果应用有未保存的用户数据,可以将其保存在此处以确保不会丢失。但是,建议在应用程序执行过程中的适当位置保存用户数据,通常是为了响应特定操作。例如,当用户关闭数据输入屏幕时保存数据。不要依赖特定的应用程序状态转换来保存应用程序的所有关键数据。

调用此方法后,该应用程序还会发布一个UIApplicationWillResignActiveNotification通知,让感兴趣的对象有机会响应转换。

参数 :

application :单例应用程序对象。

- (void)applicationDidEnterBackground:(UIApplication *)application API_AVAILABLE(ios(4.0));

函数描述通知代理应用程序现在位于后台

使用此方法来释放共享资源、使计时器失效,并存储足够的应用程序状态信息,以便在以后终止应用程序时将其恢复到当前状态。还应该禁用应用程序的用户界面更新,并避免使用某些类型的共享系统资源(如用户的联系人数据库)。还必须避免在后台使用OpenGL ES。

这个方法的实现大约有5秒钟的时间来执行任何任务并返回。如果需要额外的时间来执行最后的任务,你可以通过调用beginBackgroundTaskWithExpirationHandler:来请求额外的执行时间。实际上,应该尽快从applicationDidEnterBackground返回。如果方法在时间耗尽之前没有返回,应用程序将被终止并从内存中清除。

应该在此方法退出之前执行与调整用户界面相关的任何任务,但是其他任务(例如保存状态)应该根据需要移动到并发调度队列或辅助线程。因为在applicationDidEnterBackground:中启动的任何后台任务可能在该方法退出后才会运行,所以在启动这些任务之前,应该请求额外的后台执行时间。换句话说,首先调用beginBackgroundTaskWithExpirationHandler:然后在分派队列或辅助线程上运行任务。应用程序还会在调用此方法的同时发布UIApplicationDidEnterBackgroundNotification通知在它调用这个方法的同时给感兴趣的对象一个机会来响应转换。

参数 :

application :单例应用程序对象。

- (void)applicationWillEnterForeground:(UIApplication *)application API_AVAILABLE(ios(4.0));

函数描述通知代理应用程序即将进入前台

在iOS 4.0及更高版本中,此方法是从后台转换到活动状态的一部分。您可以使用此方法在进入后台时撤消对应用程序所做的许多更改。对该方法的调用后面总是跟着对applicationDidBecomeActive:方法的调用,然后将应用程序从非活动状态移动到活动状态。应用程序还将在调用此方法之前发布UIApplicationWillEnterForegroundNotification通知,以使感兴趣的对象有机会响应转换。

参数 :

application :单例应用程序对象。

- (void)applicationDidBecomeActive:(UIApplication *)application;

函数描述通知代理应用程序已激活

调用此方法是为了让应用程序知道它已从非活动状态移动到活动状态。这可能是因为应用程序是由用户或系统启动的。如果用户选择忽略将应用程序暂时发送到非活动状态的中断(如来电或短信),则应用程序也可以返回到活动状态。

应该使用此方法重新启动应用程序处于非活动状态时暂停(或尚未启动)的任何任务。例如,可以使用它重新启动计时器或限制OpenGL ES帧速率。如果你的应用以前在后台,你也可以使用它刷新你的应用的用户界面。在调用此方法之后,应用程序还会发布UIApplicationDidBecomeActiveNotification通知,以使感兴趣的对象有机会响应转换。

参数 :

application : 单例应用程序对象。

- (void)applicationWillTerminate:(UIApplication *)application;

函数描述通知代理应用程序将要终止

此方法让应用程序知道它将被完全终止并从内存中清除。应该使用此方法来执行应用程序的任何最终清理任务,例如释放共享资源、保存用户数据和使计时器无效。这个方法的实现大约有五秒钟的时间来执行任何任务并返回。如果方法在时间到期前不返回,系统可能会完全终止进程。

对于不支持后台执行或链接到iOS 3.x或更早版本的应用程序,当用户退出应用程序时始终调用此方法。对于支持后台执行的应用程序,当用户退出应用程序时通常不会调用此方法,因为在这种情况下,应用程序只是移动到后台。但是,如果应用程序在后台运行(未挂起),并且系统因某种原因需要终止它,则可以调用此方法。调用此方法后,应用程序还将发布UIApplicationWillTerminateNotification通知,以使感兴趣的对象有机会响应转换。

这个函数被调用的前提是 在Info.plist中设置UIApplicationExitsOnSuspend为YES,此时应用程序不会在后台运行

参数 :

application :单例应用程序对象。

- (BOOL)application:(UIApplication *)application openURL:(NSURL *)url sourceApplication:(nullable NSString *)sourceApplication annotation:(id)annotation API_DEPRECATED_WITH_REPLACEMENT("application:openURL:options:", ios(4.2, 9.0)) API_UNAVAILABLE(tvOS);

函数描述请求代理打开由URL标识的资源

此方法的实现应打开指定的URL并相应地更新其用户界面。如果必须启动应用程序才能打开URL,则应用程序首先调用:application:willFinishLaunchingWithOptions:和application: didFinishLaunchingWithOptions:方法,然后调用此方法。这些方法的返回值可用于防止调用此方法。(如果应用程序已在运行,则仅调用此方法。)

如果URL指的是通过文档交互控制器打开的文件,则annotation参数可能包含源应用程序希望与URL一起发送的其他数据。此数据的格式由发送它的应用程序定义,但数据必须包含可放入属性列表的对象。

通过AirDrop或文档交互控制器发送到应用程序的文件将放置在应用程序主目录的document s/Inbox目录中。您的应用程序具有读取和删除此目录中文件的权限,但没有写入这些文件的权限。如果要修改文件,必须先将其移动到其他目录。此外,该目录中的文件通常使用数据保护进行加密。如果文件受到保护,并且用户在调用此方法之前锁定了设备,则无法立即读取文件的内容。在这种情况下,您应该保存URL并尝试稍后打开该文件,而不是从此方法返回NO。使用app对象的protectedDataAvailable属性确定当前是否启用了数据保护。此方法没有匹配的通知。

参数 :

application : 单例应用程序对象。

url : 要打开的URL资源。此资源可以是网络资源或文件。

sourceApplication : 请求应用程序打开URL(URL)的应用程序的捆绑包ID。

annotation : 源应用程序提供的属性列表,用于将信息传递给接收应用程序。

返回值 : 如果委托成功处理了请求,则为“YES”;如果尝试打开URL资源失败,则为“NO”。

- (BOOL)application:(UIApplication *)app openURL:(NSURL *)url options:(NSDictionary<UIApplicationOpenURLOptionsKey, id> *)options API_AVAILABLE(ios(9.0));

函数描述请求代理打开由URL指定的资源,并提供启动选项字典

如果实现了application:willFinishLaunchingWithOptions:和application: didFinishLaunchingWithOptions:方法并返回NO,则不调用此方法。(如果仅实现了两个方法中的一个,则其返回值将确定是否调用此方法。)如果应用程序实现了applicationdFinishLaunching:方法而不是application:didFinishLaunchingWithOptions:,则在应用程序初始化后调用此方法以打开指定的URL。如果在应用程序挂起或在后台运行时出现URL,则系统会在调用此方法之前将应用程序移动到前台。此方法没有匹配的通知。

参数 :

app : 单例应用程序对象。

url : 要打开的URL资源。此资源可以是网络资源或文件。

options : URL处理选项的字典。默认情况下,此参数的值为空字典。

返回值 : 如果代理成功处理了请求,则为“YES”;如果尝试打开URL资源失败,则为“NO”。

- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken API_AVAILABLE(ios(3.0));

函数描述通知代理应用程序已成功注册到Apple推送通知服务(APNs)

UIKit在向APNs成功注册应用程序后调用此方法。在该方法的实现中,将deviceToken参数的内容发送到用于生成远程通知的服务器。永远不要在用户的设备上本地缓存设备令牌。设备令牌可以定期更改,因此缓存该值有可能将无效令牌发送到服务器。如果设备令牌没有更改,则向APNs注册并返回令牌会很快发生。

通常,只有在调用UIApplication的registerForRemoteNotifications方法之后才会调用此方法,但UIKit可能在其他罕见的情况下调用它。例如,UIKit在用户从非设备备份数据还原设备后启动应用程序时调用该方法。在这种特殊情况下,在用户启动新设备之前,应用程序不会知道它的令牌。

参数 :

application : 启动远程通知注册过程的应用程序对象。

deviceToken : 将此设备标识为APN的全局唯一令牌。将此令牌发送到用于生成远程通知的服务器。当发送这些远程通知时,服务器必须将未经修改的令牌传递回APNs。APNs设备令牌的长度可变。不要硬编码它们的尺寸。

- (void)application:(UIApplication *)application didFailToRegisterForRemoteNotificationsWithError:(NSError *)error API_AVAILABLE(ios(3.0));

函数描述当Apple推送通知服务无法成功完成注册过程时发送给代理

如果UIKit无法向APNs注册您的应用,或者您的应用未正确配置为远程通知,则它会调用此方法。在开发过程中,请确保您的应用具有适当的权限,并且其应用程序ID配置为支持推送通知。您可以使用此方法的实现来记录失败的注册,以便稍后再试。

参数 :

application : 启动远程通知注册过程的应用程序对象。

error : 封装注册失败原因信息的NSError对象。应用程序可以选择向用户显示此信息。

- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult result))completionHandler API_AVAILABLE(ios(7.0));

函数描述通知代理应用程序远程通知已到达,该通知指示存在要获取的数据

使用此方法处理应用程序远程通知的传入。与只在应用程序在前台运行时调用的application:didReceiveRemoteNotification:method不同,系统在应用程序在前台或后台运行时调用此方法。此外,如果启用远程通知后台模式,系统将启动应用程序(或将其从挂起状态唤醒),并在远程通知到达时将其置于后台状态。但是,如果用户强制退出应用程序,系统不会自动启动该应用程序。在这种情况下,用户必须重新启动应用程序或重新启动设备,然后系统才会尝试再次自动启动应用程序。

如果用户从系统显示的警报中打开应用程序,则当应用程序即将进入前台时,系统可能会再次调用此方法,以便您可以更新用户界面并显示与通知相关的信息。

当远程通知到达时,系统将向用户显示通知并在后台启动应用程序(如果需要),以便它可以调用此方法。在后台启动应用程序可以让您有时间处理通知并下载与之相关的任何数据,从而最大限度地缩短通知到达和向用户显示该数据之间的时间。

处理完通知后,必须在handler参数中调用块,否则应用程序将终止。应用程序最多有30秒的挂起时间来处理通知并调用指定的完成处理程序块。实际上,应该在处理完通知后立即调用处理程序块。系统会跟踪应用程序后台下载的运行时间、功耗和数据成本。在处理远程通知时使用大量电量的应用程序可能不会总是被提前唤醒来处理未来的通知。

参数 :

application : 单例应用程序对象。

userInfo : 包含与远程通知相关信息的字典,可能包括应用程序图标的徽章数(图标右上角的红色提醒数字)、警报声音、要显示给用户的警报消息、通知标识符和自定义数据。提供程序将其作为一个JSON定义的字典发起,iOS将其转换为NSDictionary对象;字典只能包含属性列表对象和NSNull。

handler : 下载操作完成后要执行的块。在调用此块时,传递fetch result值,该值最好地描述了下载操作的结果。您必须调用这个处理程序,并且应该尽快这样做。

注:UIBackgroundFetchResult的枚举值如下 :

typedef NS_ENUM(NSUInteger, UIBackgroundFetchResult) {
    UIBackgroundFetchResultNewData, //已成功下载新数据
    UIBackgroundFetchResultNoData, //没有要下载的新数据。
    UIBackgroundFetchResultFailed //尝试下载数据,但失败。
} API_AVAILABLE(ios(7.0));
- (BOOL) application:(UIApplication *)application shouldSaveApplicationState:(NSCoder *)coder API_AVAILABLE(ios(6.0));

函数描述询问代理是否应保留应用程序的状态

应用程序必须实现此方法和application:shouldRestoreApplicationState:方法才能进行状态保留。此外,每次UIKit尝试保留应用程序的状态时,此方法的实现都必须返回YES。可以返回NO以暂时禁用状态保留。例如,在测试期间,可以禁用状态保留以测试特定的代码路径。

可以根据需要将版本信息或任何其他上下文数据添加到所提供的编码器对象中。在还原过程中,可以使用该信息帮助决定是否继续将应用还原到以前的状态。

参数 :

application : 单例应用程序对象。

coder : 可以将高级状态信息放入其中的键控架构器。

返回值 : 如果应用程序的状态应该保留,则为“YES”;如果不应该保留,则为“NO”。

 - (BOOL) application:(UIApplication *)application shouldRestoreApplicationState:(NSCoder *)coder API_AVAILABLE(ios(6.0));

函数描述询问代理是否应还原应用程序的保存状态信息

应用程序必须实现此方法和application:shouldSaveApplicationState: 方法才能进行状态保留。此外,每次UIKit尝试还原应用程序的状态时,此方法的实现都必须返回“YES”。您可以使用提供的编码器对象中的信息来决定是否继续进行状态恢复。例如,如果编码器中的数据来自应用程序的其他版本,并且无法有效还原到当前版本,则可能会返回“NO”。

参数 :

application : 单例应用程序对象。

coder : 包含应用程序以前保存的状态信息的键控存档架构器。

返回值 : 如果应用程序的状态应该还原,则为“YES”;如果不应该还原,则为“NO”。

- (BOOL)application:(UIApplication *)application willFinishLaunchingWithOptions:(nullable NSDictionary<UIApplicationLaunchOptionsKey, id> *)launchOptions API_AVAILABLE(ios(6.0));

函数描述通知代理启动过程已开始,但状态还原尚未发生

使用此方法(以及相应的application: didFinishLaunchingWithOptions:方法)初始化应用程序并准备运行它。此方法在启动应用程序并加载其主情节提要或nib文件之后,但在还原应用程序的状态之前调用。调用此方法时,应用程序处于非活动状态。

如果应用程序是由系统出于特定原因启动的,则launchOptions字典包含指示启动原因的数据。由于某些启动原因,系统可能会调用应用程序委派的其他方法。例如,如果应用程序是为打开URL而启动的,则系统会在应用程序完成初始化后调用application:open URL:options:方法。启动键的出现使您有机会为这种行为制定计划。对于要打开的URL,如果URL表示用户要打开的文档,则可能需要阻止状态还原。

当要求打开一个URL时,此方法的返回结果与:application: didFinishLaunchingWithOptions:方法的返回结果相结合,以确定是否应处理URL。如果任一方法返回NO,则系统不会调用application:openURL:options:方法。如果不实现其中一个方法,则只考虑实现方法的返回值。

如果应用程序依赖于状态还原机制来还原其视图控制器,请始终使用此方法显示你的应用程序的窗口。不要在应用程序的application:didFinishLaunchingWithOptions:方法中显示窗口。调用窗口的makeKeyAndVisible方法不会立即使窗口可见。在使窗口在屏幕上可见之前,UIKit将等待应用程序的application:didFinishLaunchingWithOptions: 方法完成。

参数 :

application : 单例应用程序对象。

launchOptions : 指示应用程序启动原因的字典(如果有)。在用户直接启动应用程序的情况下,此词典的内容可能为空。

返回值 : 如果应用程序无法处理URL资源或继续用户活动,或者应用程序不应执行application:performationforshortcutitem:completionHandler:方法,因为要在此方法中处理对主屏幕快速操作的调用,则返回“NO”;否则返回“YES”。如果应用程序是作为远程通知的结果启动的,则忽略返回值。

Bug记录

[Application] The app delegate must implement the window property if it wants to use a main storyboard file.

极少情况下会发生在运行第三方的Demo中,原因是AppDelegate.h文件中@interface AppDelegate中的window属性被删掉了,导致控制台打印此提示,并且Demo运行起来是黑屏的。

例如:

@interface AppDelegate : UIResponder <UIApplicationDelegate>

//如果此属性被删掉,控制器就会打印此提示
@property (strong, nonatomic) UIWindow *window;

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

推荐阅读更多精彩内容