@@ -11,34 +11,34 @@ import Foundation
11
11
import UIKit
12
12
13
13
public protocol iOSLifecycle {
14
- func applicationDidEnterBackground( application: UIApplication )
15
- func applicationWillEnterForeground( application: UIApplication )
16
- func application( _ application: UIApplication , didFinishLaunchingWithOptions launchOptions: [ UIApplication . LaunchOptionsKey : Any ] ? )
17
- func applicationDidBecomeActive( application: UIApplication )
18
- func applicationWillResignActive( application: UIApplication )
19
- func applicationDidReceiveMemoryWarning( application: UIApplication )
20
- func applicationWillTerminate( application: UIApplication )
21
- func applicationSignificantTimeChange( application: UIApplication )
22
- func applicationBackgroundRefreshDidChange( application: UIApplication , refreshStatus: UIBackgroundRefreshStatus )
14
+ func applicationDidEnterBackground( application: UIApplication ? )
15
+ func applicationWillEnterForeground( application: UIApplication ? )
16
+ func application( _ application: UIApplication ? , didFinishLaunchingWithOptions launchOptions: [ UIApplication . LaunchOptionsKey : Any ] ? )
17
+ func applicationDidBecomeActive( application: UIApplication ? )
18
+ func applicationWillResignActive( application: UIApplication ? )
19
+ func applicationDidReceiveMemoryWarning( application: UIApplication ? )
20
+ func applicationWillTerminate( application: UIApplication ? )
21
+ func applicationSignificantTimeChange( application: UIApplication ? )
22
+ func applicationBackgroundRefreshDidChange( application: UIApplication ? , refreshStatus: UIBackgroundRefreshStatus )
23
23
}
24
24
25
25
public extension iOSLifecycle {
26
- func applicationDidEnterBackground( application: UIApplication ) { }
27
- func applicationWillEnterForeground( application: UIApplication ) { }
28
- func application( _ application: UIApplication , didFinishLaunchingWithOptions launchOptions: [ UIApplication . LaunchOptionsKey : Any ] ? ) { }
29
- func applicationDidBecomeActive( application: UIApplication ) { }
30
- func applicationWillResignActive( application: UIApplication ) { }
31
- func applicationDidReceiveMemoryWarning( application: UIApplication ) { }
32
- func applicationWillTerminate( application: UIApplication ) { }
33
- func applicationSignificantTimeChange( application: UIApplication ) { }
34
- func applicationBackgroundRefreshDidChange( application: UIApplication , refreshStatus: UIBackgroundRefreshStatus ) { }
26
+ func applicationDidEnterBackground( application: UIApplication ? ) { }
27
+ func applicationWillEnterForeground( application: UIApplication ? ) { }
28
+ func application( _ application: UIApplication ? , didFinishLaunchingWithOptions launchOptions: [ UIApplication . LaunchOptionsKey : Any ] ? ) { }
29
+ func applicationDidBecomeActive( application: UIApplication ? ) { }
30
+ func applicationWillResignActive( application: UIApplication ? ) { }
31
+ func applicationDidReceiveMemoryWarning( application: UIApplication ? ) { }
32
+ func applicationWillTerminate( application: UIApplication ? ) { }
33
+ func applicationSignificantTimeChange( application: UIApplication ? ) { }
34
+ func applicationBackgroundRefreshDidChange( application: UIApplication ? , refreshStatus: UIBackgroundRefreshStatus ) { }
35
35
}
36
36
37
37
class iOSLifecycleMonitor : PlatformPlugin {
38
38
let type = PluginType . utility
39
39
var analytics : Analytics ?
40
40
41
- private var application : UIApplication
41
+ private var application : UIApplication ? = nil
42
42
private var appNotifications : [ NSNotification . Name ] = [ UIApplication . didEnterBackgroundNotification,
43
43
UIApplication . willEnterForegroundNotification,
44
44
UIApplication . didFinishLaunchingNotification,
@@ -50,7 +50,9 @@ class iOSLifecycleMonitor: PlatformPlugin {
50
50
UIApplication . backgroundRefreshStatusDidChangeNotification]
51
51
52
52
required init ( ) {
53
- application = UIApplication . shared
53
+ // App extensions can't use UIAppication.shared, so
54
+ // funnel it through something to check; Could be nil.
55
+ application = UIApplication . safeShared
54
56
setupListeners ( )
55
57
}
56
58
@@ -154,10 +156,15 @@ class iOSLifecycleMonitor: PlatformPlugin {
154
156
}
155
157
156
158
func backgroundRefreshDidChange( notification: NSNotification ) {
157
- analytics? . apply { ( ext) in
158
- if let validExt = ext as? iOSLifecycle {
159
- validExt. applicationBackgroundRefreshDidChange ( application: application,
160
- refreshStatus: application. backgroundRefreshStatus)
159
+ // Not only would we not get this in an App Extension, but it would
160
+ // be useless since we couldn't provide the application object or
161
+ // the refreshStatus value.
162
+ if !isAppExtension, let application = UIApplication . safeShared {
163
+ analytics? . apply { ( ext) in
164
+ if let validExt = ext as? iOSLifecycle {
165
+ validExt. applicationBackgroundRefreshDidChange ( application: application,
166
+ refreshStatus: application. backgroundRefreshStatus)
167
+ }
161
168
}
162
169
}
163
170
}
@@ -166,11 +173,11 @@ class iOSLifecycleMonitor: PlatformPlugin {
166
173
// MARK: - Segment Destination Extension
167
174
168
175
extension SegmentDestination : iOSLifecycle {
169
- public func applicationWillEnterForeground( application: UIApplication ) {
176
+ public func applicationWillEnterForeground( application: UIApplication ? ) {
170
177
enterForeground ( )
171
178
}
172
179
173
- public func applicationDidEnterBackground( application: UIApplication ) {
180
+ public func applicationDidEnterBackground( application: UIApplication ? ) {
174
181
enterBackground ( )
175
182
}
176
183
}
@@ -180,15 +187,36 @@ extension SegmentDestination.UploadTaskInfo {
180
187
self . url = url
181
188
self . task = task
182
189
183
- let taskIdentifier = UIApplication . shared. beginBackgroundTask { [ self ] in
184
- self . task. suspend ( )
185
- self . cleanup ? ( )
190
+ if let application = UIApplication . safeShared {
191
+ let taskIdentifier = application. beginBackgroundTask { [ self ] in
192
+ self . task. suspend ( )
193
+ self . cleanup ? ( )
194
+ }
195
+ self . taskID = taskIdentifier. rawValue
196
+
197
+ self . cleanup = { [ self ] in
198
+ application. endBackgroundTask ( UIBackgroundTaskIdentifier ( rawValue: self . taskID) )
199
+ }
186
200
}
187
- self . taskID = taskIdentifier. rawValue
201
+ }
202
+ }
203
+
204
+ extension UIApplication {
205
+ static var safeShared : UIApplication ? {
206
+ // UIApplication.shared is not available in app extensions so try to get
207
+ // it in a way that's safe for both.
188
208
189
- self . cleanup = { [ self ] in
190
- UIApplication . shared. endBackgroundTask ( UIBackgroundTaskIdentifier ( rawValue: self . taskID) )
209
+ // if we are NOT an app extension, we need to get UIApplication.shared
210
+ if !isAppExtension {
211
+ // getting it like this allows us to avoid the compiler error that would
212
+ // be generated even though we're guarding against app extensions.
213
+ // there's no preprocessor macro or @available macro to help us here unfortunately
214
+ // so this is the best i could do.
215
+ return UIApplication . value ( forKeyPath: " sharedApplication " ) as? UIApplication
191
216
}
217
+ // if we ARE an app extension, send back nil since we have no way to get the
218
+ // application instance.
219
+ return nil
192
220
}
193
221
}
194
222
0 commit comments