├── .github ├── ISSUE_TEMPLATE.md └── PULL_REQUEST_TEMPLATE.md ├── .gitignore ├── .travis.yml ├── CHANGELOG.md ├── CONTRIBUTING.md ├── LICENSE.txt ├── Podfile ├── Podfile.lock ├── README.md ├── StartupReasonReporter.podspec ├── StartupReasonReporter.xcodeproj ├── project.pbxproj ├── project.xcworkspace │ ├── contents.xcworkspacedata │ └── xcuserdata │ │ ├── alexm.xcuserdatad │ │ └── UserInterfaceState.xcuserstate │ │ └── vince.xcuserdatad │ │ └── UserInterfaceState.xcuserstate └── xcshareddata │ └── xcschemes │ └── StartupReasonReporter.xcscheme ├── StartupReasonReporter.xcworkspace └── contents.xcworkspacedata ├── StartupReasonReporter ├── ApplicationStartupReasonReporterNotificationRelay │ ├── UBApplicationStartupReasonReporterNotificationRelay.h │ └── UBApplicationStartupReasonReporterNotificationRelay.m ├── Info.plist ├── StartupReasonReporter.h ├── StartupReasonReporter │ ├── UBApplicationStartupReasonReporter.h │ ├── UBApplicationStartupReasonReporter.m │ └── UBApplicationStartupReasonReporterPriorRunInfoProtocol.h └── StartupReasonReporterPriorRunInfo │ ├── UBApplicationStartupReasonReporterPriorRunInfo.h │ └── UBApplicationStartupReasonReporterPriorRunInfo.m ├── StartupReasonReporterTests ├── Info.plist ├── UBApplicationStartupReasonReporterNotificationRelayTests.m ├── UBApplicationStartupReasonReporterPriorRunInfoTests.m └── UBApplicationStartupReasonReporterTests.m ├── docs ├── Classes.html ├── Classes │ ├── UBApplicationStartupReasonReporter.html │ └── UBApplicationStartupReasonReporterPriorRunInfo.html ├── Constants.html ├── Protocols.html ├── Protocols │ └── UBApplicationStartupReasonReporterPriorRunInfoProtocol.html ├── Type Definitions.html ├── badge.svg ├── css │ ├── highlight.css │ └── jazzy.css ├── docsets │ ├── StartupReasonReporter.docset │ │ └── Contents │ │ │ ├── Info.plist │ │ │ └── Resources │ │ │ ├── Documents │ │ │ ├── Classes.html │ │ │ ├── Classes │ │ │ │ ├── UBApplicationStartupReasonReporter.html │ │ │ │ └── UBApplicationStartupReasonReporterPriorRunInfo.html │ │ │ ├── Constants.html │ │ │ ├── Protocols.html │ │ │ ├── Protocols │ │ │ │ └── UBApplicationStartupReasonReporterPriorRunInfoProtocol.html │ │ │ ├── Type Definitions.html │ │ │ ├── badge.svg │ │ │ ├── css │ │ │ │ ├── highlight.css │ │ │ │ └── jazzy.css │ │ │ ├── img │ │ │ │ ├── carat.png │ │ │ │ ├── dash.png │ │ │ │ └── gh.png │ │ │ ├── index.html │ │ │ ├── js │ │ │ │ ├── jazzy.js │ │ │ │ └── jquery.min.js │ │ │ ├── search.json │ │ │ └── undocumented.json │ │ │ └── docSet.dsidx │ └── StartupReasonReporter.tgz ├── img │ ├── carat.png │ ├── dash.png │ └── gh.png ├── index.html ├── js │ ├── jazzy.js │ └── jquery.min.js ├── search.json └── undocumented.json └── generate_docs.sh /.github/ISSUE_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | Thanks for using Uber's open source iOS template. Before you create an issue, please consider the following points: 2 | 3 | - [ ] If you think you found a bug, please include a code sample that reproduces the problem. A stacktrace alone is ok too, but may not contain enough context for us to deduce the issue from. 4 | 5 | - [ ] Please include the library version number, including the minor and patch version, in the issue text. 6 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | Thank you for contributing to Uber's open source iOS template. Before pressing the "Create Pull Request" button, please consider the following points: 2 | 3 | - [ ] Please give a description about what and why you are contributing, even if it's trivial. 4 | 5 | - [ ] Please include the issue list number(s) or other PR numbers in the description if you are contributing in response to those. 6 | 7 | - [ ] Please include a reasonable set of unit tests if you contribute new code or change an existing one. 8 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # OS X 2 | .DS_Store 3 | 4 | # Xcode 5 | # 6 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore 7 | 8 | ## Build generated 9 | build/ 10 | DerivedData/ 11 | 12 | ## Various settings 13 | *.pbxuser 14 | !default.pbxuser 15 | *.mode1v3 16 | !default.mode1v3 17 | *.mode2v3 18 | !default.mode2v3 19 | *.perspectivev3 20 | !default.perspectivev3 21 | xcuserdata/ 22 | 23 | ## Other 24 | *.moved-aside 25 | *.xccheckout 26 | *.xcscmblueprint 27 | 28 | ## Obj-C/Swift specific 29 | *.hmap 30 | *.ipa 31 | *.dSYM.zip 32 | *.dSYM 33 | 34 | ## Playgrounds 35 | timeline.xctimeline 36 | playground.xcworkspace 37 | 38 | # Swift Package Manager 39 | # 40 | # Add this line if you want to avoid checking in source code from Swift Package Manager dependencies. 41 | # Packages/ 42 | # Package.pins 43 | .build/ 44 | 45 | # CocoaPods 46 | # 47 | # We recommend against adding the Pods directory to your .gitignore. However 48 | # you should judge for yourself, the pros and cons are mentioned at: 49 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control 50 | # 51 | Pods/ 52 | 53 | # Carthage 54 | # 55 | # Add this line if you want to avoid checking in source code from Carthage dependencies. 56 | # Carthage/Checkouts 57 | 58 | Carthage/Build 59 | 60 | # fastlane 61 | # 62 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the 63 | # screenshots whenever they are needed. 64 | # For more information about the recommended setup visit: 65 | # https://docs.fastlane.tools/best-practices/source-control/#source-control 66 | 67 | fastlane/report.xml 68 | fastlane/Preview.html 69 | fastlane/screenshots 70 | fastlane/test_output -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: objective-c 2 | osx_image: xcode8.2 3 | xcode_project: StartupReasonReporter.xcodeproj 4 | xcode_scheme: StartupReasonReporter 5 | xcode_sdk: iphonesimulator10.2 6 | script: xcodebuild -project StartupReasonReporter.xcodeproj -scheme StartupReasonReporter -sdk iphonesimulator ONLY_ACTIVE_ARCH=NO 7 | 8 | notifications: 9 | email: false 10 | 11 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | Changelog 2 | ========= 3 | 4 | 5 | Version 0.3.0 6 | ---------------------------- 7 | 8 | * Change notification handling and storage layer to improve OOM accuracy. 9 | 10 | Version 0.2.0 11 | ---------------------------- 12 | 13 | * Expose API to set initial application state 14 | 15 | 16 | Version 0.1.1 17 | ---------------------------- 18 | 19 | * Fixed header scope in order to fix Carthage support 20 | 21 | 22 | Version 0.1.0 23 | ---------------------------- 24 | 25 | * Initial release 26 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | Contributing to Uber's iOS Template 2 | ======================= 3 | 4 | The Uber team welcomes contributions of all kinds, from simple bug reports through documentation, test cases, bugfixes, and features. 5 | 6 | Workflow 7 | -------- 8 | 9 | We love GitHub issues! 10 | 11 | For small feature requests, an issue first proposing it for discussion or demo implementation in a PR suffice. 12 | 13 | For big features, please open an issue so that we can agree on the direction, and hopefully avoid 14 | investing a lot of time on a feature that might need reworking. 15 | 16 | Small pull requests for things like typos, bugfixes, etc are always welcome. 17 | 18 | DOs and DON'Ts 19 | -------------- 20 | 21 | * DO follow our coding style (link eventually goes here) 22 | * DO include tests when adding new features. When fixing bugs, start with adding a test that highlights how the current behavior is broken. 23 | * DO keep the discussions focused. When a new or related topic comes up it's often better to create new issue than to side track the discussion. 24 | 25 | * DON'T submit PRs that alter licensing related files or headers. If you believe there's a problem with them, file an issue and we'll be happy to discuss it. 26 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2015 Uber Technologies, Inc. 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in 11 | all copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | THE SOFTWARE. -------------------------------------------------------------------------------- /Podfile: -------------------------------------------------------------------------------- 1 | platform :ios, '10.0' 2 | 3 | target 'StartupReasonReporterTests' 4 | pod 'OCMock', '~> 3.0' -------------------------------------------------------------------------------- /Podfile.lock: -------------------------------------------------------------------------------- 1 | PODS: 2 | - OCMock (3.3.1) 3 | 4 | DEPENDENCIES: 5 | - OCMock (~> 3.0) 6 | 7 | SPEC REPOS: 8 | https://github.com/cocoapods/specs.git: 9 | - OCMock 10 | 11 | SPEC CHECKSUMS: 12 | OCMock: f3f61e6eaa16038c30caa5798c5e49d3307b6f22 13 | 14 | PODFILE CHECKSUM: a4a540cd891f0fbf8a5475fde780a112960ea07c 15 | 16 | COCOAPODS: 1.5.3 17 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Startup Reason Reporter [![Build Status](https://travis-ci.org/uber/startup-reason-reporter.svg?branch=master)](https://travis-ci.org/uber/startup-reason-reporter) 2 | 3 | The Startup Reason Reporter provides developers the reason that an iOS application has launched, or equivalently, the reason that the application terminated on the prior launch. 4 | 5 | ## Use 6 | 7 | Usage is fairly straight-forward: 8 | 9 | 10 | Swift: 11 | 12 | ```swift 13 | // Determine whether the app crashed on a prior launch 14 | let crashedOnPriorLaunch = ... 15 | 16 | // Initialize a storage mechanism implementing UBApplicationStartupReasonReporterPriorRunInfoProtocol 17 | let previousRunInfo: ApplicationStartupReasonReporterProtocol = ... 18 | 19 | // Initialize the notification relay 20 | let notificationRelay = ApplicationStartupReasonReporterNotificationRelay() 21 | 22 | // Initialize the startup reason reporter 23 | let startupReasonReporter = ApplicationStartupReasonReporter(previousRunDidCrash: crashedOnPreviousLaunch, 24 | previousRunInfo: previousRunInfo, 25 | notificationRelay: notificationRelay, 26 | debugging: false) 27 | 28 | // Profit 29 | let startupReason = startupReasonReporter.startupReason 30 | 31 | // ... 32 | // In AppDelegate connect notification relay to app lifecycle methods 33 | 34 | public func applicationDidBecomeActive(_ application: UIApplication) { 35 | notificationRelay.updateApplicationStateNotification(Notification(name: .UIApplicationDidBecomeActive)) 36 | } 37 | 38 | public func applicationWillResignActive(_ application: UIApplication) { 39 | notificationRelay.updateApplicationStateNotification(Notification(name: .UIApplicationWillResignActive)) 40 | } 41 | 42 | public func applicationWillTerminate(_ application: UIApplication) { 43 | notificationRelay.updateApplicationStateNotification(Notification(name: .UIApplicationWillTerminate)) 44 | } 45 | ``` 46 | 47 | Obj-C: 48 | 49 | ```objc 50 | // Determine whether the app crashed on a prior launch 51 | BOOL crashedOnPriorLaunch = ... 52 | 53 | // Initialize a storage mechanism implementing UBApplicationStartupReasonReporterPriorRunInfoProtocol 54 | id runInfo = ... 55 | 56 | // Initialize the notification relay 57 | id = [[UBApplicationStartupReasonReporterNotificationRelay alloc] init] 58 | 59 | // Initialize the startup reason reporter 60 | UBApplicationStartupReasonReporter *startupReasonReporter = [[UBApplicationStartupReasonReporter alloc] initWithPreviousRunDidCrash:crashedOnPriorLaunch 61 | previousRunInfo:runInfo 62 | notificationRelay: notificationRelay 63 | debugging:[UBBuildType isDebugBuild]]; 64 | 65 | // Profit 66 | UBStartupReason startupReason = startupReasonReporter.startupReason 67 | 68 | // ... 69 | // In AppDelegate connect notification relay to app lifecycle methods 70 | 71 | - (void)applicationDidBecomeActive:(UIApplication *)application 72 | { 73 | [self.notificationRelay updateApplicationStateNotification:[NSNotification notificationWithName:UIApplicationDidBecomeActiveNotification object:nil]]; 74 | } 75 | 76 | - (void)applicationWillResignActive:(UIApplication *)application 77 | { 78 | [self.notificationRelay updateApplicationStateNotification:[NSNotification notificationWithName:UIApplicationWillResignActiveNotification object:nil]]; 79 | } 80 | 81 | - (void)applicationWillTerminate:(UIApplication *)application 82 | { 83 | [self.notificationRelay updateApplicationStateNotification:[NSNotification notificationWithName:UIApplicationWillTerminateNotification object:nil]]; 84 | } 85 | ``` 86 | 87 | ## Introduction 88 | 89 | The UBStartupReasonReporter is based on the general idea that applications may terminate for a fixed set of reasons on iOS. 90 | 91 | Through process of elimination, the UBStartupReasonReporter can detect important events such as OOM crashes and app upgrades. The full list of possible startup reasons is described below. 92 | 93 | Critically, the reported startup reason is only as accurate as the the data that is provided to it. For instance, some crash detection mechanisms may not encompass all forms of crashes, which may throw off the reported reason. Additionally we found that application state notifications are not always delivered, or given time to execute unless you hook into the first notification emitted by the OS, in the corresponding AppDelegate method. This is why we provide a notification relay to easily hook into these lifecycle events. 94 | 95 | Our process for detecting various startup reasons is detailed by Ali Ansari and Grzegorz Pstrucha in this blog post: [Reducing FOOMs in the iOS app](https://code.facebook.com/posts/1146930688654547/reducing-fooms-in-the-facebook-ios-app/) 96 | 97 | In order for detection to work, you must provide a class that implements prior run storage and conforms to UBApplicationStartupReasonReporterPriorRunInfoProtocol. We provide one such class, backed by the file system using JSON encoding, in UBApplicationStartupReasonReporterPriorRunInfo, though you may also wish to implement your own version that is backed by your preferred storage mechanism. 98 | 99 | Possible startup reasons are as follows: 100 | 101 | ```objc 102 | UBStartupReason const UBStartupReasonDebug = @"debug"; 103 | UBStartupReason const UBStartupReasonFirstTime = @"first_time"; 104 | UBStartupReason const UBStartupReasonCrash = @"crash"; 105 | UBStartupReason const UBStartupReasonForceQuit = @"force_quit"; 106 | UBStartupReason const UBStartupReasonAppUpgrade = @"app_upgrade"; 107 | UBStartupReason const UBStartupReasonOSUpgrade = @"os_upgrade"; 108 | UBStartupReason const UBStartupReasonBackgroundEviction = @"background_eviction"; 109 | UBStartupReason const UBStartupReasonRestart = @"restart"; 110 | UBStartupReason const UBStartupReasonOutOfMemory = @"out_of_memory"; 111 | ``` 112 | 113 | ## Installation 114 | #### CocoaPods 115 | 116 | To integrate the StartupReasonReporter into your project add the following to your `Podfile`: 117 | 118 | ```ruby 119 | pod 'StartupReasonReporter', '~> 0.2.0' 120 | ``` 121 | 122 | To integrate only the `UBApplicationStartupReasonReporterPriorRunInfoProtocol` protocol, but not the implementation, add the following to your `Podfile`: 123 | 124 | ```ruby 125 | pod 'StartupReasonReporter/Core', '~> 0.2.0' 126 | ``` 127 | 128 | #### Carthage 129 | 130 | To integrate the StartupReasonReporter into your project using Carthage add the following to your `Cartfile`: 131 | 132 | ```ruby 133 | github "uber/startup-reason-reporter" ~> 0.2.0 134 | ``` 135 | 136 | ## Contributions 137 | 138 | We'd love for you to contribute to our open source projects. Before we can accept your contributions, we kindly ask you to sign our [Uber Contributor License Agreement](https://docs.google.com/a/uber.com/forms/d/1pAwS_-dA1KhPlfxzYLBqK6rsSWwRwH95OCCZrcsY5rk/viewform). 139 | 140 | - If you **find a bug**, open an issue or submit a fix via a pull request. 141 | - If you **have a feature request**, open an issue or submit an implementation via a pull request 142 | - If you **want to contribute**, submit a pull request. 143 | 144 | ## License 145 | 146 | Copyright (c) 2015 Uber Technologies, Inc. 147 | 148 | Permission is hereby granted, free of charge, to any person obtaining a copy 149 | of this software and associated documentation files (the "Software"), to deal 150 | in the Software without restriction, including without limitation the rights 151 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 152 | copies of the Software, and to permit persons to whom the Software is 153 | furnished to do so, subject to the following conditions: 154 | 155 | The above copyright notice and this permission notice shall be included in 156 | all copies or substantial portions of the Software. 157 | 158 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 159 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 160 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 161 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 162 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 163 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 164 | THE SOFTWARE. 165 | -------------------------------------------------------------------------------- /StartupReasonReporter.podspec: -------------------------------------------------------------------------------- 1 | # 2 | # Be sure to run `pod lib lint StartupReasonReporter.podspec' to ensure this is a 3 | # valid spec before submitting. 4 | # 5 | # Any lines starting with a # are optional, but their use is encouraged 6 | # To learn more about a Podspec see http://guides.cocoapods.org/syntax/podspec.html 7 | # 8 | 9 | Pod::Spec.new do |s| 10 | s.name = 'StartupReasonReporter' 11 | s.version = '0.3.0' 12 | s.summary = 'Provides the reason that an iOS application has launched.' 13 | 14 | # This description is used to generate tags and improve search results. 15 | # * Think: What does it do? Why did you write it? What is the focus? 16 | # * Try to keep it short, snappy and to the point. 17 | # * Write the description between the DESC delimiters below. 18 | # * Finally, don't worry about the indent, CocoaPods strips it! 19 | 20 | s.description = <<-DESC 21 | The Startup Reason Reporter provides developers the the reason that an iOS application has launched, or equivalently, the reason that the application terminated on the prior launch. 22 | DESC 23 | 24 | s.homepage = 'https://github.com/uber/startup-reason-reporter' 25 | s.license = { :type => 'MIT', :file => 'LICENSE' } 26 | s.source = { :git => 'https://github.com/uber/startup-reason-reporter.git', :tag => s.version.to_s } 27 | s.author = "Uber" 28 | 29 | s.ios.deployment_target = '8.0' 30 | 31 | s.subspec 'Core' do |core| 32 | core.source_files = 'StartupReasonReporter/StartupReasonReporter/*' 33 | end 34 | 35 | s.subspec 'PriorRunInfo' do |pri| 36 | pri.source_files = 'StartupReasonReporter/StartupReasonReporterPriorRunInfo/*' 37 | pri.dependency 'StartupReasonReporter/Core' 38 | end 39 | 40 | end 41 | -------------------------------------------------------------------------------- /StartupReasonReporter.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /StartupReasonReporter.xcodeproj/project.xcworkspace/xcuserdata/alexm.xcuserdatad/UserInterfaceState.xcuserstate: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/uber/startup-reason-reporter/ad3e2d8c793a7b7a79118f0009a45cc12d74752c/StartupReasonReporter.xcodeproj/project.xcworkspace/xcuserdata/alexm.xcuserdatad/UserInterfaceState.xcuserstate -------------------------------------------------------------------------------- /StartupReasonReporter.xcodeproj/project.xcworkspace/xcuserdata/vince.xcuserdatad/UserInterfaceState.xcuserstate: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/uber/startup-reason-reporter/ad3e2d8c793a7b7a79118f0009a45cc12d74752c/StartupReasonReporter.xcodeproj/project.xcworkspace/xcuserdata/vince.xcuserdatad/UserInterfaceState.xcuserstate -------------------------------------------------------------------------------- /StartupReasonReporter.xcodeproj/xcshareddata/xcschemes/StartupReasonReporter.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 33 | 39 | 40 | 41 | 42 | 43 | 49 | 50 | 51 | 52 | 53 | 54 | 64 | 65 | 71 | 72 | 73 | 74 | 75 | 76 | 82 | 83 | 89 | 90 | 91 | 92 | 94 | 95 | 98 | 99 | 100 | -------------------------------------------------------------------------------- /StartupReasonReporter.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /StartupReasonReporter/ApplicationStartupReasonReporterNotificationRelay/UBApplicationStartupReasonReporterNotificationRelay.h: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) Uber Technologies, Inc. All rights reserved. 3 | // 4 | 5 | #import 6 | 7 | NS_ASSUME_NONNULL_BEGIN 8 | 9 | /** 10 | * Subscriber protocol which is used to respond to notifications emitted. 11 | */ 12 | NS_SWIFT_NAME(ApplicationStartupReasonReporterNotificationRelaySubscriber) 13 | @protocol UBApplicationStartupReasonReporterNotificationRelaySubscriber 14 | 15 | @required 16 | 17 | /** 18 | * Perform any work as a result of the given notification. 19 | * @param notification the notification emitted. 20 | */ 21 | - (void)processNotification:(NSNotification *)notification; 22 | 23 | @end 24 | 25 | /** 26 | * Notification relay protocol to relay notifications to a set of subscribers. 27 | */ 28 | NS_SWIFT_NAME(ApplicationStartupReasonReporterNotificationRelayProtocol) 29 | @protocol UBApplicationStartupReasonReporterNotificationRelayProtocol 30 | 31 | @required 32 | 33 | /** 34 | * Add a subscriber to the set of subscribers responding to notifications. 35 | * @param subscriber the subscriber to add. 36 | */ 37 | - (void)addSubscriber:(id)subscriber; 38 | 39 | /** 40 | * Remove a subscriber from the set of subscribers responding to notifications. 41 | * @param subscriber the subscriber to remove. 42 | */ 43 | - (void)removeSubscriber:(id)subscriber; 44 | 45 | /** 46 | * Relays the notification to the set of subscribers. 47 | * @param notification the notification to relay. 48 | */ 49 | - (void)updateApplicationStateNotification:(NSNotification *)notification; 50 | 51 | @end 52 | 53 | /** 54 | * Notification relay class to relay notifications to a set of subscribers. 55 | */ 56 | NS_SWIFT_NAME(ApplicationStartupReasonReporterNotificationRelay) 57 | @interface UBApplicationStartupReasonReporterNotificationRelay : NSObject 58 | 59 | @end 60 | 61 | NS_ASSUME_NONNULL_END 62 | -------------------------------------------------------------------------------- /StartupReasonReporter/ApplicationStartupReasonReporterNotificationRelay/UBApplicationStartupReasonReporterNotificationRelay.m: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) Uber Technologies, Inc. All rights reserved. 3 | // 4 | 5 | #import "UBApplicationStartupReasonReporterNotificationRelay.h" 6 | 7 | 8 | @interface UBApplicationStartupReasonReporterNotificationRelay () 9 | 10 | @property (nonatomic, readonly) NSMutableSet> *subscribers; 11 | @property (nonatomic, readonly) NSObject *subscribersLockToken; 12 | 13 | @end 14 | 15 | 16 | @implementation UBApplicationStartupReasonReporterNotificationRelay 17 | 18 | - (instancetype)init 19 | { 20 | self = [super init]; 21 | if (self) { 22 | _subscribers = [[NSMutableSet alloc] init]; 23 | _subscribersLockToken = [[NSObject alloc] init]; 24 | } 25 | 26 | return self; 27 | } 28 | 29 | - (void)addSubscriber:(id)subscriber 30 | { 31 | @synchronized(self.subscribersLockToken) 32 | { 33 | [self.subscribers addObject:subscriber]; 34 | } 35 | } 36 | 37 | - (void)removeSubscriber:(id)subscriber 38 | { 39 | @synchronized(self.subscribersLockToken) 40 | { 41 | [self.subscribers removeObject:subscriber]; 42 | } 43 | } 44 | 45 | - (void)updateApplicationStateNotification:(NSNotification *)notification 46 | { 47 | @synchronized(self.subscribersLockToken) 48 | { 49 | for (id subscriber in self.subscribers.allObjects) { 50 | [subscriber processNotification:notification]; 51 | } 52 | } 53 | } 54 | 55 | @end 56 | -------------------------------------------------------------------------------- /StartupReasonReporter/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleDisplayName 8 | StartupReasonReporter 9 | CFBundleExecutable 10 | $(EXECUTABLE_NAME) 11 | CFBundleIdentifier 12 | $(PRODUCT_BUNDLE_IDENTIFIER) 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | $(PRODUCT_NAME) 17 | CFBundlePackageType 18 | FMWK 19 | CFBundleShortVersionString 20 | 0.2.0 21 | CFBundleVersion 22 | $(CURRENT_PROJECT_VERSION) 23 | NSPrincipalClass 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /StartupReasonReporter/StartupReasonReporter.h: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright © 2017 Uber. All rights reserved. 3 | // 4 | 5 | #ifndef StartupReasonReporter_h 6 | #define StartupReasonReporter_h 7 | 8 | #import "UBApplicationStartupReasonReporterPriorRunInfoProtocol.h" 9 | #import "UBApplicationStartupReasonReporter.h" 10 | #import "UBApplicationStartupReasonReporterNotificationRelay.h" 11 | #import "UBApplicationStartupReasonReporterPriorRunInfo.h" 12 | 13 | 14 | #endif /* StartupReasonReporter_h */ 15 | -------------------------------------------------------------------------------- /StartupReasonReporter/StartupReasonReporter/UBApplicationStartupReasonReporter.h: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) Uber Technologies, Inc. All rights reserved. 3 | // 4 | 5 | #import 6 | #import 7 | 8 | #import "UBApplicationStartupReasonReporterNotificationRelay.h" 9 | #import "UBApplicationStartupReasonReporterPriorRunInfoProtocol.h" 10 | 11 | NS_ASSUME_NONNULL_BEGIN 12 | 13 | /// A reason that the application launched. 14 | typedef NSString *UBStartupReason NS_SWIFT_NAME(StartupReason) NS_STRING_ENUM; 15 | 16 | /// The application is being debugged. 17 | extern UBStartupReason const UBStartupReasonDebug; 18 | 19 | /// The application was started for the first time. 20 | extern UBStartupReason const UBStartupReasonFirstTime; 21 | 22 | /// The application started because it previously crashed. 23 | extern UBStartupReason const UBStartupReasonCrash; 24 | 25 | /// The application started since it was force quit on the last run. 26 | extern UBStartupReason const UBStartupReasonForceQuit; 27 | 28 | /// The application started because it was upgraded. 29 | extern UBStartupReason const UBStartupReasonAppUpgrade; 30 | 31 | /// The application started because the OS was upgraded. 32 | extern UBStartupReason const UBStartupReasonOSUpgrade; 33 | 34 | /// The application started because it was evicted from background on the last run. 35 | extern UBStartupReason const UBStartupReasonBackgroundEviction; 36 | 37 | /// The application started because the device was restarted after the last run. 38 | extern UBStartupReason const UBStartupReasonRestart; 39 | 40 | /// The application started because it ran out of memory in the foreground. 41 | extern UBStartupReason const UBStartupReasonOutOfMemory; 42 | 43 | NS_SWIFT_NAME(ApplicationStartupReasonReporter) 44 | 45 | /** 46 | The Startup Reason Reporter provides developers with the reason that an iOS application has launched, or equivalently, the reason that the application terminated on the prior launch. 47 | */ 48 | @interface UBApplicationStartupReasonReporter : NSObject 49 | 50 | /// The reason the application started up. 51 | @property (nonatomic) UBStartupReason startupReason; 52 | 53 | /// The time when the system was last booted. 54 | + (time_t)systemBootTime; 55 | 56 | /** 57 | Unavailable. 58 | */ 59 | - (instancetype)init NS_UNAVAILABLE; 60 | 61 | /** 62 | Initializes a new UBApplicationStartupReasonReporter. 63 | 64 | @param previousRunDidCrash Indicates whether the prior run was a crash 65 | @param previousRunInfo An implementation of UBApplicationStartupReasonReporterPriorRunInfoProtocol which contains information about the prior run and will store information about the current run. 66 | @param notificationRelay the relay which emits application state update notifications. 67 | @param debugging True if this app run is for debugging, false otherwise. This is useful if the app is being developed in the simulator, for instance. 68 | */ 69 | - (instancetype)initWithPreviousRunDidCrash:(BOOL)previousRunDidCrash 70 | previousRunInfo:(id)previousRunInfo 71 | notificationRelay:(id)notificationRelay 72 | debugging:(BOOL)debugging; 73 | 74 | @end 75 | 76 | NS_ASSUME_NONNULL_END 77 | -------------------------------------------------------------------------------- /StartupReasonReporter/StartupReasonReporter/UBApplicationStartupReasonReporter.m: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) Uber Technologies, Inc. All rights reserved. 3 | // 4 | 5 | #import "UBApplicationStartupReasonReporter.h" 6 | 7 | #import 8 | 9 | UBStartupReason const UBStartupReasonDebug = @"debug"; 10 | UBStartupReason const UBStartupReasonFirstTime = @"first_time"; 11 | UBStartupReason const UBStartupReasonCrash = @"crash"; 12 | UBStartupReason const UBStartupReasonForceQuit = @"force_quit"; 13 | UBStartupReason const UBStartupReasonAppUpgrade = @"app_upgrade"; 14 | UBStartupReason const UBStartupReasonOSUpgrade = @"os_upgrade"; 15 | UBStartupReason const UBStartupReasonBackgroundEviction = @"background_eviction"; 16 | UBStartupReason const UBStartupReasonRestart = @"restart"; 17 | UBStartupReason const UBStartupReasonOutOfMemory = @"out_of_memory"; 18 | 19 | 20 | @interface UBApplicationStartupReasonReporter () 21 | 22 | @property (nonatomic) BOOL previousRunDidCrash; 23 | @property (nonatomic) BOOL debugging; 24 | 25 | @property (nonatomic) NSString *previousAppVersion; 26 | @property (nonatomic) NSString *currentAppVersion; 27 | @property (nonatomic) NSString *previousOSVersion; 28 | @property (nonatomic) NSString *currentOSVersion; 29 | @property (nonatomic) time_t currentBootTime; 30 | @property (nonatomic) time_t previousBootTime; 31 | @property (nonatomic) BOOL backgrounded; 32 | @property (nonatomic) BOOL didTerminate; 33 | 34 | @property (nonatomic) id previousRunInfo; 35 | 36 | @end 37 | 38 | 39 | @implementation UBApplicationStartupReasonReporter 40 | 41 | + (time_t)systemBootTime 42 | { 43 | struct timeval boottime; 44 | size_t size = sizeof(boottime); 45 | 46 | if (sysctlbyname("kern.boottime", &boottime, &size, NULL, 0) != -1) { 47 | return boottime.tv_sec; 48 | } 49 | return 0; 50 | } 51 | 52 | - (instancetype)initWithPreviousRunDidCrash:(BOOL)previousRunDidCrash 53 | previousRunInfo:(id)previousRunInfo 54 | notificationRelay:(id)notificationRelay 55 | debugging:(BOOL)debugging 56 | { 57 | self = [super init]; 58 | if (self) { 59 | _startupReason = UBStartupReasonFirstTime; 60 | _previousRunDidCrash = previousRunDidCrash; 61 | _debugging = debugging; 62 | 63 | _currentAppVersion = [self currentBundleVersion]; 64 | _previousAppVersion = _currentAppVersion; 65 | _currentOSVersion = [[UIDevice currentDevice] systemVersion]; 66 | _previousOSVersion = _currentOSVersion; 67 | _backgrounded = NO; 68 | _didTerminate = NO; 69 | _currentBootTime = [UBApplicationStartupReasonReporter systemBootTime]; 70 | _previousBootTime = 0; 71 | 72 | _previousRunInfo = previousRunInfo; 73 | 74 | if (previousRunInfo.hasData) { 75 | if (previousRunInfo.previousAppVersion) { 76 | _previousAppVersion = previousRunInfo.previousAppVersion; 77 | } 78 | if (previousRunInfo.previousOSVersion) { 79 | _previousOSVersion = previousRunInfo.previousOSVersion; 80 | } 81 | if (previousRunInfo.backgrounded) { 82 | _backgrounded = previousRunInfo.backgrounded; 83 | } 84 | if (previousRunInfo.didTerminate) { 85 | _didTerminate = previousRunInfo.didTerminate; 86 | } 87 | if (previousRunInfo.previousBootTime) { 88 | _previousBootTime = previousRunInfo.previousBootTime; 89 | } 90 | [self _detectStartupReason]; 91 | } 92 | _didTerminate = NO; 93 | 94 | dispatch_async(dispatch_get_main_queue(), ^{ 95 | self.backgrounded = [UIApplication sharedApplication].applicationState != UIApplicationStateActive; 96 | [self _persist]; 97 | }); 98 | [notificationRelay addSubscriber:self]; 99 | } 100 | return self; 101 | } 102 | 103 | - (void)_persist 104 | { 105 | self.previousRunInfo.previousAppVersion = self.currentAppVersion ?: @""; 106 | self.previousRunInfo.previousOSVersion = self.currentOSVersion ?: @""; 107 | self.previousRunInfo.backgrounded = self.backgrounded; 108 | self.previousRunInfo.didTerminate = self.didTerminate; 109 | self.previousRunInfo.previousBootTime = self.currentBootTime; 110 | [self.previousRunInfo persist]; 111 | } 112 | 113 | - (void)_detectStartupReason 114 | { 115 | if (self.previousRunDidCrash) { 116 | self.startupReason = UBStartupReasonCrash; 117 | } else if (self.debugging) { 118 | self.startupReason = UBStartupReasonDebug; 119 | } else if (![self.previousOSVersion isEqualToString:self.currentOSVersion]) { 120 | self.startupReason = UBStartupReasonOSUpgrade; 121 | } else if (![self.previousAppVersion isEqualToString:self.currentAppVersion]) { 122 | self.startupReason = UBStartupReasonAppUpgrade; 123 | } else if (self.didTerminate) { 124 | self.startupReason = UBStartupReasonForceQuit; 125 | } else if (self.currentBootTime != self.previousBootTime) { 126 | self.startupReason = UBStartupReasonRestart; 127 | } else { 128 | if (self.backgrounded) { 129 | self.startupReason = UBStartupReasonBackgroundEviction; 130 | } else { 131 | self.startupReason = UBStartupReasonOutOfMemory; 132 | } 133 | } 134 | } 135 | 136 | - (NSString *)currentBundleVersion 137 | { 138 | return [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleVersion"]; 139 | } 140 | 141 | #pragma mark - UBApplicationStartupReasonReporterNotificationRelaySubscriber 142 | 143 | - (void)processNotification:(NSNotification *)notification 144 | { 145 | if ([notification.name isEqualToString:UIApplicationDidBecomeActiveNotification]) { 146 | self.backgrounded = NO; 147 | } else if ([notification.name isEqualToString:UIApplicationWillResignActiveNotification]) { 148 | self.backgrounded = YES; 149 | } else if ([notification.name isEqualToString:UIApplicationWillTerminateNotification]) { 150 | self.didTerminate = YES; 151 | } 152 | [self _persist]; 153 | } 154 | 155 | @end 156 | -------------------------------------------------------------------------------- /StartupReasonReporter/StartupReasonReporter/UBApplicationStartupReasonReporterPriorRunInfoProtocol.h: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) Uber Technologies, Inc. All rights reserved. 3 | // 4 | 5 | #import 6 | 7 | /** 8 | Defines a storage interface for the UBApplicationStartupReasonReporter. 9 | On launch, should contain information regarding the prior app run. 10 | When data is set thereafter, a call to persist should persist the data for the next app launch. 11 | */ 12 | 13 | NS_SWIFT_NAME(ApplicationStartupReasonReporterProtocol) 14 | 15 | @protocol UBApplicationStartupReasonReporterPriorRunInfoProtocol 16 | 17 | /// Indicates whether data exists for the prior run. Generally, this will be false on the first run and true thereafter. 18 | @property (nonatomic) BOOL hasData; 19 | /// The app version of the prior app run. 20 | @property (nonatomic, nullable, copy) NSString *previousAppVersion; 21 | /// The OS version of the prior app run. 22 | @property (nonatomic, nullable, copy) NSString *previousOSVersion; 23 | /// The boot time of the prior app run. 24 | @property (nonatomic) time_t previousBootTime; 25 | /// Indicates whether the prior app run was backgrounded. 26 | @property (nonatomic) BOOL backgrounded; 27 | /// Indicates whether the prior app run was terminated. 28 | @property (nonatomic) BOOL didTerminate; 29 | 30 | /** 31 | Persists the current prior run info to disk. 32 | */ 33 | - (void)persist; 34 | @end 35 | -------------------------------------------------------------------------------- /StartupReasonReporter/StartupReasonReporterPriorRunInfo/UBApplicationStartupReasonReporterPriorRunInfo.h: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) Uber Technologies, Inc. All rights reserved. 3 | // 4 | 5 | #import "UBApplicationStartupReasonReporterPriorRunInfoProtocol.h" 6 | 7 | #import 8 | 9 | 10 | /** 11 | An NSUserDefaults based implementation of UBApplicationStartupReasonReporterPriorRunInfoProtocol 12 | */ 13 | NS_SWIFT_NAME(ApplicationStartupReasonReporterPriorRunInfo) 14 | @interface UBApplicationStartupReasonReporterPriorRunInfo : NSObject 15 | 16 | /** 17 | * Returns the prior run information stored to disk at the given directory URL. 18 | * @param directoryURL The directory to use to to store the startup reason data. 19 | * @return the previous startup reason data if it was present on disk, or empty startup reason object. 20 | */ 21 | + (nonnull instancetype)priorRunAtDirectoryURL:(nullable NSURL *)directoryURL; 22 | 23 | @end 24 | -------------------------------------------------------------------------------- /StartupReasonReporter/StartupReasonReporterPriorRunInfo/UBApplicationStartupReasonReporterPriorRunInfo.m: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) Uber Technologies, Inc. All rights reserved. 3 | // 4 | 5 | #import "UBApplicationStartupReasonReporterPriorRunInfo.h" 6 | 7 | static NSString *const UBApplicationStartupReasonReporterDataPreviousAppVersionKey = @"prevAppVersion"; 8 | static NSString *const UBApplicationStartupReasonReporterDataPreviousOSVersionKey = @"prevOSVersion"; 9 | static NSString *const UBApplicationStartupReasonReporterDataBackgroundedKey = @"backgrounded"; 10 | static NSString *const UBApplicationStartupReasonReporterDataDidTerminateKey = @"terminate"; 11 | static NSString *const UBApplicationStartupReasonReporterDataBootTimeKey = @"prevBootTime"; 12 | 13 | static NSString *const UBApplicationStartupReasonReporterFilename = @"priorRunInfo.json"; 14 | 15 | 16 | @interface UBApplicationStartupReasonReporterPriorRunInfo () 17 | 18 | @property (nonatomic, nullable) NSURL *filepath; 19 | 20 | @end 21 | 22 | 23 | @implementation UBApplicationStartupReasonReporterPriorRunInfo 24 | 25 | @synthesize hasData = _hasData; 26 | @synthesize previousAppVersion = _previousAppVersion; 27 | @synthesize previousOSVersion = _previousOSVersion; 28 | @synthesize previousBootTime = _previousBootTime; 29 | @synthesize backgrounded = _backgrounded; 30 | @synthesize didTerminate = _didTerminate; 31 | 32 | + (nonnull instancetype)priorRunAtDirectoryURL:(nullable NSURL *)directoryURL 33 | { 34 | NSURL *filepath = [directoryURL URLByAppendingPathComponent:UBApplicationStartupReasonReporterFilename]; 35 | if (![[NSFileManager defaultManager] fileExistsAtPath:directoryURL.path isDirectory:nil]) { 36 | [[NSFileManager defaultManager] createDirectoryAtPath:directoryURL.path withIntermediateDirectories:YES attributes:nil error:nil]; 37 | } 38 | UBApplicationStartupReasonReporterPriorRunInfo *priorRunInfo = [[UBApplicationStartupReasonReporterPriorRunInfo alloc] initWithFilepath:filepath]; 39 | if (priorRunInfo == nil) { 40 | priorRunInfo = [[UBApplicationStartupReasonReporterPriorRunInfo alloc] init]; 41 | } 42 | if (filepath != nil) { 43 | priorRunInfo.filepath = filepath; 44 | } else { 45 | priorRunInfo.filepath = [[NSURL alloc] initWithString:NSSearchPathForDirectoriesInDomains(NSApplicationSupportDirectory, NSUserDomainMask, YES).firstObject]; 46 | } 47 | 48 | return priorRunInfo; 49 | } 50 | 51 | - (void)persist 52 | { 53 | self.hasData = YES; 54 | [self writeToFilepath:self.filepath]; 55 | } 56 | 57 | #pragma mark - Persistence Translation 58 | 59 | - (instancetype)initWithFilepath:(NSURL *)filepath 60 | { 61 | NSData *data = [NSData dataWithContentsOfFile:filepath.path]; 62 | NSDictionary *dictionaryRepresentation = nil; 63 | if (data != nil) { 64 | NSError *error = nil; 65 | dictionaryRepresentation = [NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:&error]; 66 | NSAssert(error == nil, @"error found when deserializing startup reason data: %@", error.localizedDescription); 67 | } 68 | self = [super init]; 69 | if (self) { 70 | if (dictionaryRepresentation != nil) { 71 | _hasData = YES; 72 | if ([dictionaryRepresentation[UBApplicationStartupReasonReporterDataPreviousAppVersionKey] isKindOfClass:[NSString class]]) { 73 | _previousAppVersion = dictionaryRepresentation[UBApplicationStartupReasonReporterDataPreviousAppVersionKey]; 74 | } 75 | if ([dictionaryRepresentation[UBApplicationStartupReasonReporterDataPreviousOSVersionKey] isKindOfClass:[NSString class]]) { 76 | _previousOSVersion = dictionaryRepresentation[UBApplicationStartupReasonReporterDataPreviousOSVersionKey]; 77 | } 78 | if ([dictionaryRepresentation[UBApplicationStartupReasonReporterDataBootTimeKey] isKindOfClass:[NSNumber class]]) { 79 | _previousBootTime = [dictionaryRepresentation[UBApplicationStartupReasonReporterDataBootTimeKey] integerValue]; 80 | } 81 | if ([dictionaryRepresentation[UBApplicationStartupReasonReporterDataBackgroundedKey] isKindOfClass:[NSNumber class]]) { 82 | _backgrounded = [dictionaryRepresentation[UBApplicationStartupReasonReporterDataBackgroundedKey] boolValue]; 83 | } 84 | if ([dictionaryRepresentation[UBApplicationStartupReasonReporterDataDidTerminateKey] isKindOfClass:[NSNumber class]]) { 85 | _didTerminate = [dictionaryRepresentation[UBApplicationStartupReasonReporterDataDidTerminateKey] boolValue]; 86 | } 87 | } 88 | } 89 | 90 | return self; 91 | } 92 | 93 | - (void)writeToFilepath:(NSURL *)filepath 94 | { 95 | NSMutableDictionary *dictionaryRepresentation = [NSMutableDictionary dictionary]; 96 | if (self.previousAppVersion != nil) { 97 | dictionaryRepresentation[UBApplicationStartupReasonReporterDataPreviousAppVersionKey] = self.previousAppVersion; 98 | } 99 | if (self.previousOSVersion) { 100 | dictionaryRepresentation[UBApplicationStartupReasonReporterDataPreviousOSVersionKey] = self.previousOSVersion; 101 | } 102 | dictionaryRepresentation[UBApplicationStartupReasonReporterDataBootTimeKey] = [NSNumber numberWithInteger:self.previousBootTime]; 103 | dictionaryRepresentation[UBApplicationStartupReasonReporterDataBackgroundedKey] = [NSNumber numberWithBool:self.backgrounded]; 104 | dictionaryRepresentation[UBApplicationStartupReasonReporterDataDidTerminateKey] = [NSNumber numberWithBool:self.didTerminate]; 105 | NSError *error = nil; 106 | NSData *data = [NSJSONSerialization dataWithJSONObject:dictionaryRepresentation options:kNilOptions error:&error]; 107 | NSAssert(error == nil, @"error found when serializing startup reason object: %@", error.localizedDescription); 108 | error = nil; 109 | [data writeToFile:filepath.path options:NSDataWritingAtomic error:&error]; 110 | NSAssert(error == nil, @"error found when writing startup reason object: %@", error.localizedDescription); 111 | } 112 | 113 | @end 114 | -------------------------------------------------------------------------------- /StartupReasonReporterTests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | 22 | 23 | -------------------------------------------------------------------------------- /StartupReasonReporterTests/UBApplicationStartupReasonReporterNotificationRelayTests.m: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) Uber Technologies, Inc. All rights reserved. 3 | // 4 | 5 | #import "UBApplicationStartupReasonReporterNotificationRelay.h" 6 | #import 7 | #import 8 | 9 | 10 | @interface UBApplicationStartupReasonReporterNotificationRelay () 11 | 12 | @property (nonatomic, readonly) NSMutableSet> *subscribers; 13 | 14 | @end 15 | 16 | 17 | @interface UBApplicationStartupReasonReporterNotificationRelayTests : XCTestCase 18 | 19 | @end 20 | 21 | 22 | @implementation UBApplicationStartupReasonReporterNotificationRelayTests 23 | 24 | - (void)test_addSubscriber 25 | { 26 | id subscriber1 = OCMProtocolMock(@protocol(UBApplicationStartupReasonReporterNotificationRelaySubscriber)); 27 | id subscriber2 = OCMProtocolMock(@protocol(UBApplicationStartupReasonReporterNotificationRelaySubscriber)); 28 | 29 | UBApplicationStartupReasonReporterNotificationRelay *relay = [[UBApplicationStartupReasonReporterNotificationRelay alloc] init]; 30 | [relay addSubscriber:subscriber1]; 31 | [relay addSubscriber:subscriber2]; 32 | 33 | XCTAssert([relay.subscribers containsObject:subscriber1]); 34 | XCTAssert([relay.subscribers containsObject:subscriber2]); 35 | } 36 | 37 | - (void)test_removeSubscriber 38 | { 39 | id subscriber1 = OCMProtocolMock(@protocol(UBApplicationStartupReasonReporterNotificationRelaySubscriber)); 40 | id subscriber2 = OCMProtocolMock(@protocol(UBApplicationStartupReasonReporterNotificationRelaySubscriber)); 41 | 42 | UBApplicationStartupReasonReporterNotificationRelay *relay = [[UBApplicationStartupReasonReporterNotificationRelay alloc] init]; 43 | [relay addSubscriber:subscriber1]; 44 | [relay addSubscriber:subscriber2]; 45 | [relay removeSubscriber:subscriber1]; 46 | [relay removeSubscriber:subscriber2]; 47 | 48 | XCTAssertFalse([relay.subscribers containsObject:subscriber1]); 49 | XCTAssertFalse([relay.subscribers containsObject:subscriber2]); 50 | } 51 | 52 | - (void)test_updateApplicationStateNotification 53 | { 54 | id subscriber1 = OCMProtocolMock(@protocol(UBApplicationStartupReasonReporterNotificationRelaySubscriber)); 55 | id subscriber2 = OCMProtocolMock(@protocol(UBApplicationStartupReasonReporterNotificationRelaySubscriber)); 56 | NSNotification *notification = [[NSNotification alloc] initWithName:UIApplicationWillResignActiveNotification object:nil userInfo:nil]; 57 | 58 | UBApplicationStartupReasonReporterNotificationRelay *relay = [[UBApplicationStartupReasonReporterNotificationRelay alloc] init]; 59 | [relay addSubscriber:subscriber1]; 60 | [relay addSubscriber:subscriber2]; 61 | OCMExpect([subscriber1 processNotification:notification]); 62 | OCMExpect([subscriber2 processNotification:notification]); 63 | [relay updateApplicationStateNotification:notification]; 64 | OCMVerifyAll(subscriber1); 65 | OCMVerifyAll(subscriber2); 66 | } 67 | 68 | @end 69 | -------------------------------------------------------------------------------- /StartupReasonReporterTests/UBApplicationStartupReasonReporterPriorRunInfoTests.m: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) Uber Technologies, Inc. All rights reserved. 3 | // 4 | 5 | #import "UBApplicationStartupReasonReporterPriorRunInfo.h" 6 | #import 7 | #import 8 | 9 | 10 | @interface UBApplicationStartupReasonReporterPriorRunInfoTests : XCTestCase 11 | 12 | @end 13 | 14 | 15 | @implementation UBApplicationStartupReasonReporterPriorRunInfoTests 16 | 17 | - (void)test_priorRunAtDirectoryURL 18 | { 19 | NSMutableDictionary *dictionaryRepresentation = [NSMutableDictionary dictionary]; 20 | dictionaryRepresentation[@"prevAppVersion"] = @"test_version"; 21 | dictionaryRepresentation[@"prevOSVersion"] = @"test_os_version"; 22 | dictionaryRepresentation[@"prevBootTime"] = [NSNumber numberWithInteger:1]; 23 | dictionaryRepresentation[@"backgrounded"] = [NSNumber numberWithBool:YES]; 24 | dictionaryRepresentation[@"terminate"] = [NSNumber numberWithBool:YES]; 25 | NSData *data = [NSJSONSerialization dataWithJSONObject:dictionaryRepresentation options:kNilOptions error:nil]; 26 | 27 | NSURL *url = [NSURL URLWithString:@"test"]; 28 | id NSDataMock = OCMClassMock([NSData class]); 29 | OCMStub([NSDataMock dataWithContentsOfFile:[url URLByAppendingPathComponent:@"priorRunInfo.json"].path]).andReturn(data); 30 | UBApplicationStartupReasonReporterPriorRunInfo *info = [UBApplicationStartupReasonReporterPriorRunInfo priorRunAtDirectoryURL:url]; 31 | 32 | XCTAssertTrue([info.previousAppVersion isEqualToString:@"test_version"]); 33 | XCTAssertTrue([info.previousOSVersion isEqualToString:@"test_os_version"]); 34 | XCTAssertTrue(info.previousBootTime == 1); 35 | XCTAssertTrue(info.backgrounded); 36 | XCTAssertTrue(info.didTerminate); 37 | } 38 | 39 | - (void)test_persist 40 | { 41 | __block UBApplicationStartupReasonReporterPriorRunInfo *info = [[UBApplicationStartupReasonReporterPriorRunInfo alloc] init]; 42 | info.previousAppVersion = @"test_version"; 43 | info.previousOSVersion = @"test_os_version"; 44 | info.previousBootTime = 1; 45 | info.backgrounded = YES; 46 | info.didTerminate = YES; 47 | 48 | id NSJSONSerializationMock = OCMClassMock([NSJSONSerialization class]); 49 | id dataMock = OCMPartialMock([NSData data]); 50 | OCMStub([NSJSONSerializationMock dataWithJSONObject:OCMOCK_ANY options:kNilOptions error:[OCMArg anyObjectRef]]).andDo(^(NSInvocation *invocation) { 51 | __unsafe_unretained NSDictionary *dict = nil; 52 | [invocation getArgument:&dict atIndex:2]; 53 | 54 | XCTAssertTrue([dict[@"prevAppVersion"] isEqualToString:info.previousAppVersion]); 55 | XCTAssertTrue([dict[@"prevOSVersion"] isEqualToString:info.previousOSVersion]); 56 | XCTAssertTrue([dict[@"backgrounded"] boolValue]); 57 | XCTAssertTrue([dict[@"terminate"] boolValue]); 58 | XCTAssertTrue([dict[@"prevBootTime"] integerValue] == 1); 59 | }).andReturn(dataMock); 60 | OCMStub([dataMock writeToFile:OCMOCK_ANY options:NSDataWritingAtomic error:[OCMArg anyObjectRef]]).andReturn(YES); 61 | [info persist]; 62 | OCMVerify([dataMock writeToFile:OCMOCK_ANY options:NSDataWritingAtomic error:[OCMArg anyObjectRef]]); 63 | } 64 | 65 | @end 66 | -------------------------------------------------------------------------------- /StartupReasonReporterTests/UBApplicationStartupReasonReporterTests.m: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) Uber Technologies, Inc. All rights reserved. 3 | // 4 | 5 | #import "UBApplicationStartupReasonReporter.h" 6 | #import "UBApplicationStartupReasonReporterNotificationRelay.h" 7 | #import "UBApplicationStartupReasonReporterPriorRunInfo.h" 8 | #import 9 | #import 10 | 11 | 12 | @interface UBApplicationStartupReasonReporter () 13 | 14 | @end 15 | 16 | 17 | @interface UBApplicationStartupReasonReporterTests : XCTestCase 18 | 19 | @property (nonatomic) NSString *currentAppVersion; 20 | @property (nonatomic) NSString *currentOSVersion; 21 | @property (nonatomic) id sharedApplicationMock; 22 | @property (nonatomic) id previousStartupMock; 23 | @property (nonatomic) id notificationRelayMock; 24 | 25 | @property (nonatomic) NSArray *mocks; 26 | 27 | 28 | @end 29 | 30 | 31 | @implementation UBApplicationStartupReasonReporterTests 32 | 33 | - (void)setUp 34 | { 35 | [super setUp]; 36 | self.currentAppVersion = @"2.0"; 37 | self.currentOSVersion = @"9.0"; 38 | 39 | id mainBundleMock = OCMPartialMock([NSBundle mainBundle]); 40 | OCMStub([mainBundleMock infoDictionary]).andReturn(@{ @"CFBundleVersion" : self.currentAppVersion }); 41 | id NSBundleMock = OCMClassMock([NSBundle class]); 42 | OCMStub([NSBundleMock mainBundle]).andReturn(mainBundleMock); 43 | 44 | id deviceMock = OCMPartialMock([UIDevice currentDevice]); 45 | OCMStub([(UIDevice *)deviceMock systemVersion]).andReturn(self.currentOSVersion); 46 | id UIDeviceMock = OCMClassMock([UIDevice class]); 47 | OCMStub([UIDeviceMock currentDevice]).andReturn(deviceMock); 48 | 49 | self.sharedApplicationMock = OCMPartialMock([UIApplication alloc]); 50 | id UIApplicationMock = OCMClassMock([UIApplication class]); 51 | OCMStub([UIApplicationMock sharedApplication]).andReturn(self.sharedApplicationMock); 52 | 53 | self.previousStartupMock = OCMProtocolMock(@protocol(UBApplicationStartupReasonReporterPriorRunInfoProtocol)); 54 | self.notificationRelayMock = OCMProtocolMock(@protocol(UBApplicationStartupReasonReporterNotificationRelayProtocol)); 55 | 56 | self.mocks = @[ mainBundleMock, NSBundleMock, deviceMock, UIDeviceMock, self.sharedApplicationMock, UIApplicationMock, self.previousStartupMock, self.notificationRelayMock ]; 57 | } 58 | 59 | - (void)tearDown 60 | { 61 | [super tearDown]; 62 | 63 | for (id mock in self.mocks) { 64 | [mock stopMocking]; 65 | } 66 | } 67 | 68 | - (void)test_init_notificationRelaySubscribe 69 | { 70 | id notificationRelayMock = OCMProtocolMock(@protocol(UBApplicationStartupReasonReporterNotificationRelayProtocol)); 71 | OCMStub([self.sharedApplicationMock applicationState]).andReturn(UIApplicationStateActive); 72 | 73 | OCMExpect([notificationRelayMock addSubscriber:OCMOCK_ANY]); 74 | 75 | id previousStartupMock = OCMProtocolMock(@protocol(UBApplicationStartupReasonReporterPriorRunInfoProtocol)); 76 | UBApplicationStartupReasonReporter *reporter = [[UBApplicationStartupReasonReporter alloc] 77 | initWithPreviousRunDidCrash:NO 78 | previousRunInfo:previousStartupMock 79 | notificationRelay:notificationRelayMock 80 | debugging:NO]; 81 | 82 | XCTAssertNotNil(reporter); 83 | } 84 | 85 | - (void)test_init_whenBackgroundingOrForegrounding_persistsChange 86 | { 87 | id notificationRelay = [[UBApplicationStartupReasonReporterNotificationRelay alloc] init]; 88 | OCMStub([self.sharedApplicationMock applicationState]).andReturn(UIApplicationStateActive); 89 | 90 | UBApplicationStartupReasonReporter *reporter = [[UBApplicationStartupReasonReporter alloc] 91 | initWithPreviousRunDidCrash:NO 92 | previousRunInfo:self.previousStartupMock 93 | notificationRelay:notificationRelay 94 | debugging:NO]; 95 | XCTAssertNotNil(reporter); 96 | 97 | OCMExpect([self.previousStartupMock setBackgrounded:YES]); 98 | OCMExpect([self.previousStartupMock setPreviousAppVersion:@"2.0"]); 99 | OCMExpect([self.previousStartupMock setPreviousOSVersion:@"9.0"]); 100 | OCMExpect([self.previousStartupMock setDidTerminate:NO]); 101 | OCMExpect([self.previousStartupMock setPreviousBootTime:[UBApplicationStartupReasonReporter systemBootTime]]); 102 | OCMExpect([self.previousStartupMock persist]); 103 | 104 | [notificationRelay updateApplicationStateNotification:[NSNotification notificationWithName:UIApplicationWillResignActiveNotification object:nil]]; 105 | OCMVerifyAll(self.previousStartupMock); 106 | 107 | OCMExpect([self.previousStartupMock setBackgrounded:NO]); 108 | OCMExpect([self.previousStartupMock persist]); 109 | 110 | [notificationRelay updateApplicationStateNotification:[NSNotification notificationWithName:UIApplicationDidBecomeActiveNotification object:nil]]; 111 | OCMVerifyAll(self.previousStartupMock); 112 | } 113 | 114 | - (void)test_init_whenTerminating_persistsChange 115 | { 116 | id notificationRelay = [[UBApplicationStartupReasonReporterNotificationRelay alloc] init]; 117 | OCMStub([self.sharedApplicationMock applicationState]).andReturn(UIApplicationStateActive); 118 | 119 | UBApplicationStartupReasonReporter *reporter = [[UBApplicationStartupReasonReporter alloc] 120 | initWithPreviousRunDidCrash:NO 121 | previousRunInfo:self.previousStartupMock 122 | notificationRelay:notificationRelay 123 | debugging:NO]; 124 | XCTAssertNotNil(reporter); 125 | [notificationRelay updateApplicationStateNotification:[NSNotification notificationWithName:UIApplicationWillResignActiveNotification object:nil]]; 126 | 127 | OCMExpect([self.previousStartupMock setBackgrounded:YES]); 128 | OCMExpect([self.previousStartupMock setPreviousAppVersion:@"2.0"]); 129 | OCMExpect([self.previousStartupMock setPreviousOSVersion:@"9.0"]); 130 | OCMExpect([self.previousStartupMock setDidTerminate:YES]); 131 | OCMExpect([self.previousStartupMock setPreviousBootTime:[UBApplicationStartupReasonReporter systemBootTime]]); 132 | OCMExpect([self.previousStartupMock persist]); 133 | 134 | [notificationRelay updateApplicationStateNotification:[NSNotification notificationWithName:UIApplicationWillTerminateNotification object:nil]]; 135 | OCMVerifyAll(self.previousStartupMock); 136 | } 137 | 138 | - (void)test_init_correctStartupReason 139 | { 140 | OCMStub([self.sharedApplicationMock applicationState]).andReturn(UIApplicationStateActive); 141 | 142 | UBApplicationStartupReasonReporter *reporter = [[UBApplicationStartupReasonReporter alloc] 143 | initWithPreviousRunDidCrash:NO 144 | previousRunInfo:self.previousStartupMock 145 | notificationRelay:self.notificationRelayMock 146 | debugging:NO]; 147 | XCTAssertEqualObjects(reporter.startupReason, UBStartupReasonFirstTime); 148 | 149 | [self verifyStartupReasonIs:UBStartupReasonAppUpgrade 150 | withBackgrounded:NO 151 | prevAppVersion:@"1.0" 152 | prevOSVersion:@"9.0" 153 | terminate:NO 154 | prevBootTime:[UBApplicationStartupReasonReporter systemBootTime] 155 | previousRunDidCrash:NO 156 | debugging:NO]; 157 | 158 | [self verifyStartupReasonIs:UBStartupReasonOSUpgrade 159 | withBackgrounded:YES 160 | prevAppVersion:@"2.0" 161 | prevOSVersion:@"8.0" 162 | terminate:NO 163 | prevBootTime:[UBApplicationStartupReasonReporter systemBootTime] 164 | previousRunDidCrash:NO 165 | debugging:NO]; 166 | 167 | [self verifyStartupReasonIs:UBStartupReasonForceQuit 168 | withBackgrounded:YES 169 | prevAppVersion:@"2.0" 170 | prevOSVersion:@"9.0" 171 | terminate:YES 172 | prevBootTime:[UBApplicationStartupReasonReporter systemBootTime] 173 | previousRunDidCrash:NO 174 | debugging:NO]; 175 | 176 | [self verifyStartupReasonIs:UBStartupReasonBackgroundEviction 177 | withBackgrounded:YES 178 | prevAppVersion:@"2.0" 179 | prevOSVersion:@"9.0" 180 | terminate:NO 181 | prevBootTime:[UBApplicationStartupReasonReporter systemBootTime] 182 | previousRunDidCrash:NO 183 | debugging:NO]; 184 | 185 | [self verifyStartupReasonIs:UBStartupReasonOutOfMemory 186 | withBackgrounded:NO 187 | prevAppVersion:@"2.0" 188 | prevOSVersion:@"9.0" 189 | terminate:NO 190 | prevBootTime:[UBApplicationStartupReasonReporter systemBootTime] 191 | previousRunDidCrash:NO 192 | debugging:NO]; 193 | 194 | [self verifyStartupReasonIs:UBStartupReasonCrash 195 | withBackgrounded:YES 196 | prevAppVersion:@"2.0" 197 | prevOSVersion:@"9.0" 198 | terminate:YES 199 | prevBootTime:[UBApplicationStartupReasonReporter systemBootTime] 200 | previousRunDidCrash:YES 201 | debugging:NO]; 202 | 203 | [self verifyStartupReasonIs:UBStartupReasonRestart 204 | withBackgrounded:NO 205 | prevAppVersion:@"2.0" 206 | prevOSVersion:@"9.0" 207 | terminate:NO 208 | prevBootTime:([UBApplicationStartupReasonReporter systemBootTime] - 100) 209 | previousRunDidCrash:NO 210 | debugging:NO]; 211 | 212 | [self verifyStartupReasonIs:UBStartupReasonDebug 213 | withBackgrounded:YES 214 | prevAppVersion:@"2.0" 215 | prevOSVersion:@"9.0" 216 | terminate:YES 217 | prevBootTime:([UBApplicationStartupReasonReporter systemBootTime]) 218 | previousRunDidCrash:NO 219 | debugging:YES]; 220 | } 221 | 222 | - (void)verifyStartupReasonIs:(NSString *)startupReason 223 | withBackgrounded:(BOOL)backgrounded 224 | prevAppVersion:(NSString *)prevAppVersion 225 | prevOSVersion:(NSString *)prevOSVersion 226 | terminate:(BOOL)terminate 227 | prevBootTime:(time_t)prevBootTime 228 | previousRunDidCrash:(BOOL)previousRunDidCrash 229 | debugging:(BOOL)debugging 230 | { 231 | id previousStartupMock = OCMProtocolMock(@protocol(UBApplicationStartupReasonReporterPriorRunInfoProtocol)); 232 | id notificationRelayMock = OCMProtocolMock(@protocol(UBApplicationStartupReasonReporterNotificationRelayProtocol)); 233 | OCMStub([previousStartupMock hasData]).andReturn(YES); 234 | OCMStub([previousStartupMock backgrounded]).andReturn(backgrounded); 235 | OCMStub([previousStartupMock previousAppVersion]).andReturn(prevAppVersion); 236 | OCMStub([previousStartupMock previousOSVersion]).andReturn(prevOSVersion); 237 | OCMStub([previousStartupMock didTerminate]).andReturn(terminate); 238 | OCMStub([previousStartupMock previousBootTime]).andReturn(prevBootTime); 239 | UBApplicationStartupReasonReporter *reporter = [[UBApplicationStartupReasonReporter alloc] 240 | initWithPreviousRunDidCrash:previousRunDidCrash 241 | previousRunInfo:previousStartupMock 242 | notificationRelay:notificationRelayMock 243 | debugging:debugging]; 244 | 245 | XCTAssertEqualObjects(startupReason, reporter.startupReason); 246 | } 247 | 248 | @end 249 | -------------------------------------------------------------------------------- /docs/Classes.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Classes Reference 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 |
16 |

StartupReasonReporter Docs (100% documented)

17 |

View on GitHub

18 |
19 |
20 |
21 | 26 |
27 |
28 | 91 |
92 |
93 |
94 |

Classes

95 |

The following classes are available globally.

96 | 97 |
98 |
99 |
100 |
    101 |
  • 102 |
    103 | 104 | 105 | 106 | UBApplicationStartupReasonReporter 107 | 108 |
    109 |
    110 |
    111 |
    112 |
    113 |
    114 |

    The Startup Reason Reporter provides developers with the reason that an iOS application has launched, or equivalently, the reason that the application terminated on the prior launch.

    115 | 116 | See more 117 |
    118 |
    119 |

    Declaration

    120 |
    121 |

    Objective-C

    122 |
    @interface UBApplicationStartupReasonReporter : NSObject
    123 | 124 |
    125 |
    126 |

    Swift

    127 |
    class ApplicationStartupReasonReporter : NSObject
    128 | 129 |
    130 |
    131 |
    132 |
    133 |
  • 134 |
135 |
136 |
137 |
    138 |
  • 139 |
    140 | 141 | 142 | 143 | UBApplicationStartupReasonReporterPriorRunInfo 144 | 145 |
    146 |
    147 |
    148 |
    149 |
    150 |
    151 |

    An NSUserDefaults based implementation of UBApplicationStartupReasonReporterPriorRunInfoProtocol

    152 | 153 | See more 154 |
    155 |
    156 |

    Declaration

    157 |
    158 |

    Objective-C

    159 |
    @interface UBApplicationStartupReasonReporterPriorRunInfo
    160 |     : NSObject <UBApplicationStartupReasonReporterPriorRunInfoProtocol>
    161 | 162 |
    163 |
    164 |

    Swift

    165 |
    class ApplicationStartupReasonReporterPriorRunInfo : NSObject
    166 | 167 |
    168 |
    169 |
    170 |
    171 |
  • 172 |
173 |
174 |
175 |
176 | 180 |
181 |
182 | 183 | 184 | 185 | -------------------------------------------------------------------------------- /docs/Classes/UBApplicationStartupReasonReporter.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | UBApplicationStartupReasonReporter Class Reference 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 |
17 |

StartupReasonReporter Docs (100% documented)

18 |

View on GitHub

19 |
20 |
21 |
22 | 27 |
28 |
29 | 92 |
93 |
94 |
95 |

UBApplicationStartupReasonReporter

96 |
97 |
98 |
@interface UBApplicationStartupReasonReporter : NSObject
99 | 100 |
101 |
102 |

The Startup Reason Reporter provides developers with the reason that an iOS application has launched, or equivalently, the reason that the application terminated on the prior launch.

103 | 104 |
105 |
106 |
107 |
    108 |
  • 109 |
    110 | 111 | 112 | 113 | startupReason 114 | 115 |
    116 |
    117 |
    118 |
    119 |
    120 |
    121 |

    The reason the application started up.

    122 | 123 |
    124 |
    125 |

    Declaration

    126 |
    127 |

    Objective-C

    128 |
    @property (assign, readwrite, nonatomic) UBStartupReason _Nonnull startupReason;
    129 | 130 |
    131 |
    132 |

    Swift

    133 |
    var startupReason: StartupReason { get set }
    134 | 135 |
    136 |
    137 |
    138 |
    139 |
  • 140 |
  • 141 |
    142 | 143 | 144 | 145 | +systemBootTime 146 | 147 |
    148 |
    149 |
    150 |
    151 |
    152 |
    153 |

    The time when the system was last booted.

    154 | 155 |
    156 |
    157 |

    Declaration

    158 |
    159 |

    Objective-C

    160 |
    + (time_t)systemBootTime;
    161 | 162 |
    163 |
    164 |

    Swift

    165 |
    class func systemBootTime() -> time_t
    166 | 167 |
    168 |
    169 |
    170 |
    171 |
  • 172 |
  • 173 |
    174 | 175 | 176 | 177 | -init 178 | 179 |
    180 |
    181 |
    182 |
    183 |
    184 |
    185 |

    Unavailable.

    186 | 187 |
    188 |
    189 |

    Declaration

    190 |
    191 |

    Objective-C

    192 |
    - (nonnull instancetype)init;
    193 | 194 |
    195 |
    196 |
    197 |
    198 |
  • 199 |
  • 200 | 207 |
    208 |
    209 |
    210 |
    211 |
    212 |

    Initializes a new UBApplicationStartupReasonReporter.

    213 | 214 |
    215 |
    216 |

    Declaration

    217 |
    218 |

    Objective-C

    219 |
    - (nonnull instancetype)
    220 | initWithNotificationCenter:(nonnull NSNotificationCenter *)notificationCenter
    221 |        previousRunDidCrash:(BOOL)previousRunDidCrash
    222 |            previousRunInfo:
    223 |                (nonnull
    224 |                     id<UBApplicationStartupReasonReporterPriorRunInfoProtocol>)
    225 |                    previousRunInfo
    226 |                  debugging:(BOOL)debugging;
    227 | 228 |
    229 |
    230 |

    Swift

    231 |
    init(notificationCenter: NotificationCenter, previousRunDidCrash: Bool, previousRunInfo: ApplicationStartupReasonReporterProtocol, debugging: Bool)
    232 | 233 |
    234 |
    235 |
    236 |

    Parameters

    237 | 238 | 239 | 240 | 245 | 251 | 252 | 253 | 258 | 264 | 265 | 266 | 271 | 277 | 278 | 279 | 284 | 290 | 291 | 292 |
    241 | 242 | notificationCenter 243 | 244 | 246 |
    247 |

    The current NSNotificationCenter

    248 | 249 |
    250 |
    254 | 255 | previousRunDidCrash 256 | 257 | 259 |
    260 |

    Indicates whether the prior run was a crash

    261 | 262 |
    263 |
    267 | 268 | previousRunInfo 269 | 270 | 272 |
    273 |

    An implementation of UBApplicationStartupReasonReporterPriorRunInfoProtocol which contains information about the prior run and will store information about the current run.

    274 | 275 |
    276 |
    280 | 281 | debugging 282 | 283 | 285 |
    286 |

    True if this app run is for debugging, false otherwise. This is useful if the app is being developed in the simulator, for instance.

    287 | 288 |
    289 |
    293 |
    294 |
    295 |
    296 |
  • 297 |
298 |
299 |
300 |
301 | 305 |
306 |
307 | 308 | 309 | 310 | -------------------------------------------------------------------------------- /docs/Classes/UBApplicationStartupReasonReporterPriorRunInfo.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | UBApplicationStartupReasonReporterPriorRunInfo Class Reference 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 |
17 |

StartupReasonReporter Docs (100% documented)

18 |

View on GitHub

19 |
20 |
21 |
22 | 27 |
28 |
29 | 92 |
93 |
94 |
95 |

UBApplicationStartupReasonReporterPriorRunInfo

96 |
97 |
98 |
@interface UBApplicationStartupReasonReporterPriorRunInfo
 99 |     : NSObject <UBApplicationStartupReasonReporterPriorRunInfoProtocol>
100 | 101 |
102 |
103 |

An NSUserDefaults based implementation of UBApplicationStartupReasonReporterPriorRunInfoProtocol

104 | 105 |
106 |
107 |
108 |
    109 |
  • 110 |
    111 | 112 | 113 | 114 | -initWithUserDefaults: 115 | 116 |
    117 |
    118 |
    119 |
    120 |
    121 |
    122 |

    Initializes a new UBApplicationStartupReasonReporterPriorRunInfo

    123 | 124 |
    125 |
    126 |

    Declaration

    127 |
    128 |

    Objective-C

    129 |
    - (nonnull instancetype)initWithUserDefaults:
    130 |     (nonnull NSUserDefaults *)userDefaults;
    131 | 132 |
    133 |
    134 |

    Swift

    135 |
    init(userDefaults: UserDefaults)
    136 | 137 |
    138 |
    139 |
    140 |

    Parameters

    141 | 142 | 143 | 144 | 149 | 155 | 156 | 157 |
    145 | 146 | userDefaults 147 | 148 | 150 |
    151 |

    The current user defaults

    152 | 153 |
    154 |
    158 |
    159 |
    160 |
    161 |
  • 162 |
163 |
164 |
165 |
166 | 170 |
171 |
172 | 173 | 174 | 175 | -------------------------------------------------------------------------------- /docs/Protocols.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Protocols Reference 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 |
16 |

StartupReasonReporter Docs (100% documented)

17 |

View on GitHub

18 |
19 |
20 |
21 | 26 |
27 |
28 | 91 |
92 |
93 |
94 |

Protocols

95 |

The following protocols are available globally.

96 | 97 |
98 |
99 |
100 |
    101 |
  • 102 |
    103 | 104 | 105 | 106 | UBApplicationStartupReasonReporterPriorRunInfoProtocol 107 | 108 |
    109 |
    110 |
    111 |
    112 |
    113 |
    114 |

    Defines a storage interface for the UBApplicationStartupReasonReporter. 115 | On launch, should contain information regarding the prior app run. 116 | When data is set thereafter, a call to persist should persist the data for the next app launch.

    117 | 118 | See more 119 |
    120 |
    121 |

    Declaration

    122 |
    123 |

    Objective-C

    124 |
    @protocol UBApplicationStartupReasonReporterPriorRunInfoProtocol
    125 | 126 |
    127 |
    128 |

    Swift

    129 |
    protocol ApplicationStartupReasonReporterProtocol
    130 | 131 |
    132 |
    133 |
    134 |
    135 |
  • 136 |
137 |
138 |
139 |
140 | 144 |
145 |
146 | 147 | 148 | 149 | -------------------------------------------------------------------------------- /docs/Type Definitions.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Type Definitions Reference 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 |
16 |

StartupReasonReporter Docs (100% documented)

17 |

View on GitHub

18 |
19 |
20 |
21 | 26 |
27 |
28 | 91 |
92 |
93 |
94 |

Type Definitions

95 |

The following type definitions are available globally.

96 | 97 |
98 |
99 |
100 |
    101 |
  • 102 |
    103 | 104 | 105 | 106 | UBStartupReason 107 | 108 |
    109 |
    110 |
    111 |
    112 |
    113 |
    114 |

    A reason that the application launched.

    115 | 116 |
    117 |
    118 |

    Declaration

    119 |
    120 |

    Objective-C

    121 |
    typedef NSString *UBStartupReason
    122 | 123 |
    124 |
    125 |

    Swift

    126 |
    struct StartupReason : RawRepresentable, _SwiftNewtypeWrapper, Equatable, Hashable, Comparable, _ObjectiveCBridgeable
    127 | 128 |
    129 |
    130 |
    131 |
    132 |
  • 133 |
134 |
135 |
136 |
137 | 141 |
142 |
143 | 144 | 145 | 146 | -------------------------------------------------------------------------------- /docs/badge.svg: -------------------------------------------------------------------------------- 1 | documentationdocumentation100%100% -------------------------------------------------------------------------------- /docs/css/highlight.css: -------------------------------------------------------------------------------- 1 | /* Credit to https://gist.github.com/wataru420/2048287 */ 2 | .highlight { 3 | /* Comment */ 4 | /* Error */ 5 | /* Keyword */ 6 | /* Operator */ 7 | /* Comment.Multiline */ 8 | /* Comment.Preproc */ 9 | /* Comment.Single */ 10 | /* Comment.Special */ 11 | /* Generic.Deleted */ 12 | /* Generic.Deleted.Specific */ 13 | /* Generic.Emph */ 14 | /* Generic.Error */ 15 | /* Generic.Heading */ 16 | /* Generic.Inserted */ 17 | /* Generic.Inserted.Specific */ 18 | /* Generic.Output */ 19 | /* Generic.Prompt */ 20 | /* Generic.Strong */ 21 | /* Generic.Subheading */ 22 | /* Generic.Traceback */ 23 | /* Keyword.Constant */ 24 | /* Keyword.Declaration */ 25 | /* Keyword.Pseudo */ 26 | /* Keyword.Reserved */ 27 | /* Keyword.Type */ 28 | /* Literal.Number */ 29 | /* Literal.String */ 30 | /* Name.Attribute */ 31 | /* Name.Builtin */ 32 | /* Name.Class */ 33 | /* Name.Constant */ 34 | /* Name.Entity */ 35 | /* Name.Exception */ 36 | /* Name.Function */ 37 | /* Name.Namespace */ 38 | /* Name.Tag */ 39 | /* Name.Variable */ 40 | /* Operator.Word */ 41 | /* Text.Whitespace */ 42 | /* Literal.Number.Float */ 43 | /* Literal.Number.Hex */ 44 | /* Literal.Number.Integer */ 45 | /* Literal.Number.Oct */ 46 | /* Literal.String.Backtick */ 47 | /* Literal.String.Char */ 48 | /* Literal.String.Doc */ 49 | /* Literal.String.Double */ 50 | /* Literal.String.Escape */ 51 | /* Literal.String.Heredoc */ 52 | /* Literal.String.Interpol */ 53 | /* Literal.String.Other */ 54 | /* Literal.String.Regex */ 55 | /* Literal.String.Single */ 56 | /* Literal.String.Symbol */ 57 | /* Name.Builtin.Pseudo */ 58 | /* Name.Variable.Class */ 59 | /* Name.Variable.Global */ 60 | /* Name.Variable.Instance */ 61 | /* Literal.Number.Integer.Long */ } 62 | .highlight .c { 63 | color: #999988; 64 | font-style: italic; } 65 | .highlight .err { 66 | color: #a61717; 67 | background-color: #e3d2d2; } 68 | .highlight .k { 69 | color: #000000; 70 | font-weight: bold; } 71 | .highlight .o { 72 | color: #000000; 73 | font-weight: bold; } 74 | .highlight .cm { 75 | color: #999988; 76 | font-style: italic; } 77 | .highlight .cp { 78 | color: #999999; 79 | font-weight: bold; } 80 | .highlight .c1 { 81 | color: #999988; 82 | font-style: italic; } 83 | .highlight .cs { 84 | color: #999999; 85 | font-weight: bold; 86 | font-style: italic; } 87 | .highlight .gd { 88 | color: #000000; 89 | background-color: #ffdddd; } 90 | .highlight .gd .x { 91 | color: #000000; 92 | background-color: #ffaaaa; } 93 | .highlight .ge { 94 | color: #000000; 95 | font-style: italic; } 96 | .highlight .gr { 97 | color: #aa0000; } 98 | .highlight .gh { 99 | color: #999999; } 100 | .highlight .gi { 101 | color: #000000; 102 | background-color: #ddffdd; } 103 | .highlight .gi .x { 104 | color: #000000; 105 | background-color: #aaffaa; } 106 | .highlight .go { 107 | color: #888888; } 108 | .highlight .gp { 109 | color: #555555; } 110 | .highlight .gs { 111 | font-weight: bold; } 112 | .highlight .gu { 113 | color: #aaaaaa; } 114 | .highlight .gt { 115 | color: #aa0000; } 116 | .highlight .kc { 117 | color: #000000; 118 | font-weight: bold; } 119 | .highlight .kd { 120 | color: #000000; 121 | font-weight: bold; } 122 | .highlight .kp { 123 | color: #000000; 124 | font-weight: bold; } 125 | .highlight .kr { 126 | color: #000000; 127 | font-weight: bold; } 128 | .highlight .kt { 129 | color: #445588; } 130 | .highlight .m { 131 | color: #009999; } 132 | .highlight .s { 133 | color: #d14; } 134 | .highlight .na { 135 | color: #008080; } 136 | .highlight .nb { 137 | color: #0086B3; } 138 | .highlight .nc { 139 | color: #445588; 140 | font-weight: bold; } 141 | .highlight .no { 142 | color: #008080; } 143 | .highlight .ni { 144 | color: #800080; } 145 | .highlight .ne { 146 | color: #990000; 147 | font-weight: bold; } 148 | .highlight .nf { 149 | color: #990000; } 150 | .highlight .nn { 151 | color: #555555; } 152 | .highlight .nt { 153 | color: #000080; } 154 | .highlight .nv { 155 | color: #008080; } 156 | .highlight .ow { 157 | color: #000000; 158 | font-weight: bold; } 159 | .highlight .w { 160 | color: #bbbbbb; } 161 | .highlight .mf { 162 | color: #009999; } 163 | .highlight .mh { 164 | color: #009999; } 165 | .highlight .mi { 166 | color: #009999; } 167 | .highlight .mo { 168 | color: #009999; } 169 | .highlight .sb { 170 | color: #d14; } 171 | .highlight .sc { 172 | color: #d14; } 173 | .highlight .sd { 174 | color: #d14; } 175 | .highlight .s2 { 176 | color: #d14; } 177 | .highlight .se { 178 | color: #d14; } 179 | .highlight .sh { 180 | color: #d14; } 181 | .highlight .si { 182 | color: #d14; } 183 | .highlight .sx { 184 | color: #d14; } 185 | .highlight .sr { 186 | color: #009926; } 187 | .highlight .s1 { 188 | color: #d14; } 189 | .highlight .ss { 190 | color: #990073; } 191 | .highlight .bp { 192 | color: #999999; } 193 | .highlight .vc { 194 | color: #008080; } 195 | .highlight .vg { 196 | color: #008080; } 197 | .highlight .vi { 198 | color: #008080; } 199 | .highlight .il { 200 | color: #009999; } 201 | -------------------------------------------------------------------------------- /docs/css/jazzy.css: -------------------------------------------------------------------------------- 1 | html, body, div, span, h1, h3, h4, p, a, code, em, img, ul, li, table, tbody, tr, td { 2 | background: transparent; 3 | border: 0; 4 | margin: 0; 5 | outline: 0; 6 | padding: 0; 7 | vertical-align: baseline; } 8 | 9 | body { 10 | background-color: #f2f2f2; 11 | font-family: Helvetica, freesans, Arial, sans-serif; 12 | font-size: 14px; 13 | -webkit-font-smoothing: subpixel-antialiased; 14 | word-wrap: break-word; } 15 | 16 | h1, h2, h3 { 17 | margin-top: 0.8em; 18 | margin-bottom: 0.3em; 19 | font-weight: 100; 20 | color: black; } 21 | 22 | h1 { 23 | font-size: 2.5em; } 24 | 25 | h2 { 26 | font-size: 2em; 27 | border-bottom: 1px solid #e2e2e2; } 28 | 29 | h4 { 30 | font-size: 13px; 31 | line-height: 1.5; 32 | margin-top: 21px; } 33 | 34 | h5 { 35 | font-size: 1.1em; } 36 | 37 | h6 { 38 | font-size: 1.1em; 39 | color: #777; } 40 | 41 | .section-name { 42 | color: gray; 43 | display: block; 44 | font-family: Helvetica; 45 | font-size: 22px; 46 | font-weight: 100; 47 | margin-bottom: 15px; } 48 | 49 | pre, code { 50 | font: 0.95em Menlo, monospace; 51 | color: #777; 52 | word-wrap: normal; } 53 | 54 | p code, li code { 55 | background-color: #eee; 56 | padding: 2px 4px; 57 | border-radius: 4px; } 58 | 59 | a { 60 | color: #0088cc; 61 | text-decoration: none; } 62 | 63 | ul { 64 | padding-left: 15px; } 65 | 66 | li { 67 | line-height: 1.8em; } 68 | 69 | img { 70 | max-width: 100%; } 71 | 72 | blockquote { 73 | margin-left: 0; 74 | padding: 0 10px; 75 | border-left: 4px solid #ccc; } 76 | 77 | .content-wrapper { 78 | margin: 0 auto; 79 | width: 980px; } 80 | 81 | header { 82 | font-size: 0.85em; 83 | line-height: 26px; 84 | background-color: #414141; 85 | position: fixed; 86 | width: 100%; 87 | z-index: 1; } 88 | header img { 89 | padding-right: 6px; 90 | vertical-align: -4px; 91 | height: 16px; } 92 | header a { 93 | color: #fff; } 94 | header p { 95 | float: left; 96 | color: #999; } 97 | header .header-right { 98 | float: right; 99 | margin-left: 16px; } 100 | 101 | #breadcrumbs { 102 | background-color: #f2f2f2; 103 | height: 27px; 104 | padding-top: 17px; 105 | position: fixed; 106 | width: 100%; 107 | z-index: 1; 108 | margin-top: 26px; } 109 | #breadcrumbs #carat { 110 | height: 10px; 111 | margin: 0 5px; } 112 | 113 | .sidebar { 114 | background-color: #f9f9f9; 115 | border: 1px solid #e2e2e2; 116 | overflow-y: auto; 117 | overflow-x: hidden; 118 | position: fixed; 119 | top: 70px; 120 | bottom: 0; 121 | width: 230px; 122 | word-wrap: normal; } 123 | 124 | .nav-groups { 125 | list-style-type: none; 126 | background: #fff; 127 | padding-left: 0; } 128 | 129 | .nav-group-name { 130 | border-bottom: 1px solid #e2e2e2; 131 | font-size: 1.1em; 132 | font-weight: 100; 133 | padding: 15px 0 15px 20px; } 134 | .nav-group-name > a { 135 | color: #333; } 136 | 137 | .nav-group-tasks { 138 | margin-top: 5px; } 139 | 140 | .nav-group-task { 141 | font-size: 0.9em; 142 | list-style-type: none; 143 | white-space: nowrap; } 144 | .nav-group-task a { 145 | color: #888; } 146 | 147 | .main-content { 148 | background-color: #fff; 149 | border: 1px solid #e2e2e2; 150 | margin-left: 246px; 151 | position: absolute; 152 | overflow: hidden; 153 | padding-bottom: 60px; 154 | top: 70px; 155 | width: 734px; } 156 | .main-content p, .main-content a, .main-content code, .main-content em, .main-content ul, .main-content table, .main-content blockquote { 157 | margin-bottom: 1em; } 158 | .main-content p { 159 | line-height: 1.8em; } 160 | .main-content section .section:first-child { 161 | margin-top: 0; 162 | padding-top: 0; } 163 | .main-content section .task-group-section .task-group:first-of-type { 164 | padding-top: 10px; } 165 | .main-content section .task-group-section .task-group:first-of-type .section-name { 166 | padding-top: 15px; } 167 | 168 | .section { 169 | padding: 0 25px; } 170 | 171 | .highlight { 172 | background-color: #eee; 173 | padding: 10px 12px; 174 | border: 1px solid #e2e2e2; 175 | border-radius: 4px; 176 | overflow-x: auto; } 177 | 178 | .declaration .highlight { 179 | overflow-x: initial; 180 | padding: 0 40px 40px 0; 181 | margin-bottom: -25px; 182 | background-color: transparent; 183 | border: none; } 184 | 185 | .section-name { 186 | margin: 0; 187 | margin-left: 18px; } 188 | 189 | .task-group-section { 190 | padding-left: 6px; 191 | border-top: 1px solid #e2e2e2; } 192 | 193 | .task-group { 194 | padding-top: 0px; } 195 | 196 | .task-name-container a[name]:before { 197 | content: ""; 198 | display: block; 199 | padding-top: 70px; 200 | margin: -70px 0 0; } 201 | 202 | .item { 203 | padding-top: 8px; 204 | width: 100%; 205 | list-style-type: none; } 206 | .item a[name]:before { 207 | content: ""; 208 | display: block; 209 | padding-top: 70px; 210 | margin: -70px 0 0; } 211 | .item code { 212 | background-color: transparent; 213 | padding: 0; } 214 | .item .token { 215 | padding-left: 3px; 216 | margin-left: 15px; 217 | font-size: 11.9px; } 218 | .item .declaration-note { 219 | font-size: .85em; 220 | color: gray; 221 | font-style: italic; } 222 | 223 | .pointer-container { 224 | border-bottom: 1px solid #e2e2e2; 225 | left: -23px; 226 | padding-bottom: 13px; 227 | position: relative; 228 | width: 110%; } 229 | 230 | .pointer { 231 | background: #f9f9f9; 232 | border-left: 1px solid #e2e2e2; 233 | border-top: 1px solid #e2e2e2; 234 | height: 12px; 235 | left: 21px; 236 | top: -7px; 237 | -webkit-transform: rotate(45deg); 238 | -moz-transform: rotate(45deg); 239 | -o-transform: rotate(45deg); 240 | transform: rotate(45deg); 241 | position: absolute; 242 | width: 12px; } 243 | 244 | .height-container { 245 | display: none; 246 | left: -25px; 247 | padding: 0 25px; 248 | position: relative; 249 | width: 100%; 250 | overflow: hidden; } 251 | .height-container .section { 252 | background: #f9f9f9; 253 | border-bottom: 1px solid #e2e2e2; 254 | left: -25px; 255 | position: relative; 256 | width: 100%; 257 | padding-top: 10px; 258 | padding-bottom: 5px; } 259 | 260 | .aside, .language { 261 | padding: 6px 12px; 262 | margin: 12px 0; 263 | border-left: 5px solid #dddddd; 264 | overflow-y: hidden; } 265 | .aside .aside-title, .language .aside-title { 266 | font-size: 9px; 267 | letter-spacing: 2px; 268 | text-transform: uppercase; 269 | padding-bottom: 0; 270 | margin: 0; 271 | color: #aaa; 272 | -webkit-user-select: none; } 273 | .aside p:last-child, .language p:last-child { 274 | margin-bottom: 0; } 275 | 276 | .language { 277 | border-left: 5px solid #cde9f4; } 278 | .language .aside-title { 279 | color: #4b8afb; } 280 | 281 | .aside-warning { 282 | border-left: 5px solid #ff6666; } 283 | .aside-warning .aside-title { 284 | color: #ff0000; } 285 | 286 | .graybox { 287 | border-collapse: collapse; 288 | width: 100%; } 289 | .graybox p { 290 | margin: 0; 291 | word-break: break-word; 292 | min-width: 50px; } 293 | .graybox td { 294 | border: 1px solid #e2e2e2; 295 | padding: 5px 25px 5px 10px; 296 | vertical-align: middle; } 297 | .graybox tr td:first-of-type { 298 | text-align: right; 299 | padding: 7px; 300 | vertical-align: top; 301 | word-break: normal; 302 | width: 40px; } 303 | 304 | .slightly-smaller { 305 | font-size: 0.9em; } 306 | 307 | #footer { 308 | position: absolute; 309 | bottom: 10px; 310 | margin-left: 25px; } 311 | #footer p { 312 | margin: 0; 313 | color: #aaa; 314 | font-size: 0.8em; } 315 | 316 | html.dash header, html.dash #breadcrumbs, html.dash .sidebar { 317 | display: none; } 318 | html.dash .main-content { 319 | width: 980px; 320 | margin-left: 0; 321 | border: none; 322 | width: 100%; 323 | top: 0; 324 | padding-bottom: 0; } 325 | html.dash .height-container { 326 | display: block; } 327 | html.dash .item .token { 328 | margin-left: 0; } 329 | html.dash .content-wrapper { 330 | width: auto; } 331 | html.dash #footer { 332 | position: static; } 333 | -------------------------------------------------------------------------------- /docs/docsets/StartupReasonReporter.docset/Contents/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleIdentifier 6 | com.jazzy.startupreasonreporter 7 | CFBundleName 8 | StartupReasonReporter 9 | DocSetPlatformFamily 10 | startupreasonreporter 11 | isDashDocset 12 | 13 | dashIndexFilePath 14 | index.html 15 | isJavaScriptEnabled 16 | 17 | DashDocSetFamily 18 | dashtoc 19 | 20 | 21 | -------------------------------------------------------------------------------- /docs/docsets/StartupReasonReporter.docset/Contents/Resources/Documents/Classes.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Classes Reference 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 |
16 |

StartupReasonReporter Docs (100% documented)

17 |

View on GitHub

18 |
19 |
20 |
21 | 26 |
27 |
28 | 91 |
92 |
93 |
94 |

Classes

95 |

The following classes are available globally.

96 | 97 |
98 |
99 |
100 |
    101 |
  • 102 |
    103 | 104 | 105 | 106 | UBApplicationStartupReasonReporter 107 | 108 |
    109 |
    110 |
    111 |
    112 |
    113 |
    114 |

    The Startup Reason Reporter provides developers with the reason that an iOS application has launched, or equivalently, the reason that the application terminated on the prior launch.

    115 | 116 | See more 117 |
    118 |
    119 |

    Declaration

    120 |
    121 |

    Objective-C

    122 |
    @interface UBApplicationStartupReasonReporter : NSObject
    123 | 124 |
    125 |
    126 |

    Swift

    127 |
    class ApplicationStartupReasonReporter : NSObject
    128 | 129 |
    130 |
    131 |
    132 |
    133 |
  • 134 |
135 |
136 |
137 |
    138 |
  • 139 |
    140 | 141 | 142 | 143 | UBApplicationStartupReasonReporterPriorRunInfo 144 | 145 |
    146 |
    147 |
    148 |
    149 |
    150 |
    151 |

    An NSUserDefaults based implementation of UBApplicationStartupReasonReporterPriorRunInfoProtocol

    152 | 153 | See more 154 |
    155 |
    156 |

    Declaration

    157 |
    158 |

    Objective-C

    159 |
    @interface UBApplicationStartupReasonReporterPriorRunInfo
    160 |     : NSObject <UBApplicationStartupReasonReporterPriorRunInfoProtocol>
    161 | 162 |
    163 |
    164 |

    Swift

    165 |
    class ApplicationStartupReasonReporterPriorRunInfo : NSObject
    166 | 167 |
    168 |
    169 |
    170 |
    171 |
  • 172 |
173 |
174 |
175 |
176 | 180 |
181 |
182 | 183 | 184 | 185 | -------------------------------------------------------------------------------- /docs/docsets/StartupReasonReporter.docset/Contents/Resources/Documents/Classes/UBApplicationStartupReasonReporterPriorRunInfo.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | UBApplicationStartupReasonReporterPriorRunInfo Class Reference 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 |
17 |

StartupReasonReporter Docs (100% documented)

18 |

View on GitHub

19 |
20 |
21 |
22 | 27 |
28 |
29 | 92 |
93 |
94 |
95 |

UBApplicationStartupReasonReporterPriorRunInfo

96 |
97 |
98 |
@interface UBApplicationStartupReasonReporterPriorRunInfo
 99 |     : NSObject <UBApplicationStartupReasonReporterPriorRunInfoProtocol>
100 | 101 |
102 |
103 |

An NSUserDefaults based implementation of UBApplicationStartupReasonReporterPriorRunInfoProtocol

104 | 105 |
106 |
107 |
108 |
    109 |
  • 110 |
    111 | 112 | 113 | 114 | -initWithUserDefaults: 115 | 116 |
    117 |
    118 |
    119 |
    120 |
    121 |
    122 |

    Initializes a new UBApplicationStartupReasonReporterPriorRunInfo

    123 | 124 |
    125 |
    126 |

    Declaration

    127 |
    128 |

    Objective-C

    129 |
    - (nonnull instancetype)initWithUserDefaults:
    130 |     (nonnull NSUserDefaults *)userDefaults;
    131 | 132 |
    133 |
    134 |

    Swift

    135 |
    init(userDefaults: UserDefaults)
    136 | 137 |
    138 |
    139 |
    140 |

    Parameters

    141 | 142 | 143 | 144 | 149 | 155 | 156 | 157 |
    145 | 146 | userDefaults 147 | 148 | 150 |
    151 |

    The current user defaults

    152 | 153 |
    154 |
    158 |
    159 |
    160 |
    161 |
  • 162 |
163 |
164 |
165 |
166 | 170 |
171 |
172 | 173 | 174 | 175 | -------------------------------------------------------------------------------- /docs/docsets/StartupReasonReporter.docset/Contents/Resources/Documents/Protocols.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Protocols Reference 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 |
16 |

StartupReasonReporter Docs (100% documented)

17 |

View on GitHub

18 |
19 |
20 |
21 | 26 |
27 |
28 | 91 |
92 |
93 |
94 |

Protocols

95 |

The following protocols are available globally.

96 | 97 |
98 |
99 |
100 |
    101 |
  • 102 |
    103 | 104 | 105 | 106 | UBApplicationStartupReasonReporterPriorRunInfoProtocol 107 | 108 |
    109 |
    110 |
    111 |
    112 |
    113 |
    114 |

    Defines a storage interface for the UBApplicationStartupReasonReporter. 115 | On launch, should contain information regarding the prior app run. 116 | When data is set thereafter, a call to persist should persist the data for the next app launch.

    117 | 118 | See more 119 |
    120 |
    121 |

    Declaration

    122 |
    123 |

    Objective-C

    124 |
    @protocol UBApplicationStartupReasonReporterPriorRunInfoProtocol
    125 | 126 |
    127 |
    128 |

    Swift

    129 |
    protocol ApplicationStartupReasonReporterProtocol
    130 | 131 |
    132 |
    133 |
    134 |
    135 |
  • 136 |
137 |
138 |
139 |
140 | 144 |
145 |
146 | 147 | 148 | 149 | -------------------------------------------------------------------------------- /docs/docsets/StartupReasonReporter.docset/Contents/Resources/Documents/Type Definitions.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Type Definitions Reference 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 |
16 |

StartupReasonReporter Docs (100% documented)

17 |

View on GitHub

18 |
19 |
20 |
21 | 26 |
27 |
28 | 91 |
92 |
93 |
94 |

Type Definitions

95 |

The following type definitions are available globally.

96 | 97 |
98 |
99 |
100 |
    101 |
  • 102 |
    103 | 104 | 105 | 106 | UBStartupReason 107 | 108 |
    109 |
    110 |
    111 |
    112 |
    113 |
    114 |

    A reason that the application launched.

    115 | 116 |
    117 |
    118 |

    Declaration

    119 |
    120 |

    Objective-C

    121 |
    typedef NSString *UBStartupReason
    122 | 123 |
    124 |
    125 |

    Swift

    126 |
    struct StartupReason : RawRepresentable, _SwiftNewtypeWrapper, Equatable, Hashable, Comparable, _ObjectiveCBridgeable
    127 | 128 |
    129 |
    130 |
    131 |
    132 |
  • 133 |
134 |
135 |
136 |
137 | 141 |
142 |
143 | 144 | 145 | 146 | -------------------------------------------------------------------------------- /docs/docsets/StartupReasonReporter.docset/Contents/Resources/Documents/badge.svg: -------------------------------------------------------------------------------- 1 | documentationdocumentation100%100% -------------------------------------------------------------------------------- /docs/docsets/StartupReasonReporter.docset/Contents/Resources/Documents/css/highlight.css: -------------------------------------------------------------------------------- 1 | /* Credit to https://gist.github.com/wataru420/2048287 */ 2 | .highlight { 3 | /* Comment */ 4 | /* Error */ 5 | /* Keyword */ 6 | /* Operator */ 7 | /* Comment.Multiline */ 8 | /* Comment.Preproc */ 9 | /* Comment.Single */ 10 | /* Comment.Special */ 11 | /* Generic.Deleted */ 12 | /* Generic.Deleted.Specific */ 13 | /* Generic.Emph */ 14 | /* Generic.Error */ 15 | /* Generic.Heading */ 16 | /* Generic.Inserted */ 17 | /* Generic.Inserted.Specific */ 18 | /* Generic.Output */ 19 | /* Generic.Prompt */ 20 | /* Generic.Strong */ 21 | /* Generic.Subheading */ 22 | /* Generic.Traceback */ 23 | /* Keyword.Constant */ 24 | /* Keyword.Declaration */ 25 | /* Keyword.Pseudo */ 26 | /* Keyword.Reserved */ 27 | /* Keyword.Type */ 28 | /* Literal.Number */ 29 | /* Literal.String */ 30 | /* Name.Attribute */ 31 | /* Name.Builtin */ 32 | /* Name.Class */ 33 | /* Name.Constant */ 34 | /* Name.Entity */ 35 | /* Name.Exception */ 36 | /* Name.Function */ 37 | /* Name.Namespace */ 38 | /* Name.Tag */ 39 | /* Name.Variable */ 40 | /* Operator.Word */ 41 | /* Text.Whitespace */ 42 | /* Literal.Number.Float */ 43 | /* Literal.Number.Hex */ 44 | /* Literal.Number.Integer */ 45 | /* Literal.Number.Oct */ 46 | /* Literal.String.Backtick */ 47 | /* Literal.String.Char */ 48 | /* Literal.String.Doc */ 49 | /* Literal.String.Double */ 50 | /* Literal.String.Escape */ 51 | /* Literal.String.Heredoc */ 52 | /* Literal.String.Interpol */ 53 | /* Literal.String.Other */ 54 | /* Literal.String.Regex */ 55 | /* Literal.String.Single */ 56 | /* Literal.String.Symbol */ 57 | /* Name.Builtin.Pseudo */ 58 | /* Name.Variable.Class */ 59 | /* Name.Variable.Global */ 60 | /* Name.Variable.Instance */ 61 | /* Literal.Number.Integer.Long */ } 62 | .highlight .c { 63 | color: #999988; 64 | font-style: italic; } 65 | .highlight .err { 66 | color: #a61717; 67 | background-color: #e3d2d2; } 68 | .highlight .k { 69 | color: #000000; 70 | font-weight: bold; } 71 | .highlight .o { 72 | color: #000000; 73 | font-weight: bold; } 74 | .highlight .cm { 75 | color: #999988; 76 | font-style: italic; } 77 | .highlight .cp { 78 | color: #999999; 79 | font-weight: bold; } 80 | .highlight .c1 { 81 | color: #999988; 82 | font-style: italic; } 83 | .highlight .cs { 84 | color: #999999; 85 | font-weight: bold; 86 | font-style: italic; } 87 | .highlight .gd { 88 | color: #000000; 89 | background-color: #ffdddd; } 90 | .highlight .gd .x { 91 | color: #000000; 92 | background-color: #ffaaaa; } 93 | .highlight .ge { 94 | color: #000000; 95 | font-style: italic; } 96 | .highlight .gr { 97 | color: #aa0000; } 98 | .highlight .gh { 99 | color: #999999; } 100 | .highlight .gi { 101 | color: #000000; 102 | background-color: #ddffdd; } 103 | .highlight .gi .x { 104 | color: #000000; 105 | background-color: #aaffaa; } 106 | .highlight .go { 107 | color: #888888; } 108 | .highlight .gp { 109 | color: #555555; } 110 | .highlight .gs { 111 | font-weight: bold; } 112 | .highlight .gu { 113 | color: #aaaaaa; } 114 | .highlight .gt { 115 | color: #aa0000; } 116 | .highlight .kc { 117 | color: #000000; 118 | font-weight: bold; } 119 | .highlight .kd { 120 | color: #000000; 121 | font-weight: bold; } 122 | .highlight .kp { 123 | color: #000000; 124 | font-weight: bold; } 125 | .highlight .kr { 126 | color: #000000; 127 | font-weight: bold; } 128 | .highlight .kt { 129 | color: #445588; } 130 | .highlight .m { 131 | color: #009999; } 132 | .highlight .s { 133 | color: #d14; } 134 | .highlight .na { 135 | color: #008080; } 136 | .highlight .nb { 137 | color: #0086B3; } 138 | .highlight .nc { 139 | color: #445588; 140 | font-weight: bold; } 141 | .highlight .no { 142 | color: #008080; } 143 | .highlight .ni { 144 | color: #800080; } 145 | .highlight .ne { 146 | color: #990000; 147 | font-weight: bold; } 148 | .highlight .nf { 149 | color: #990000; } 150 | .highlight .nn { 151 | color: #555555; } 152 | .highlight .nt { 153 | color: #000080; } 154 | .highlight .nv { 155 | color: #008080; } 156 | .highlight .ow { 157 | color: #000000; 158 | font-weight: bold; } 159 | .highlight .w { 160 | color: #bbbbbb; } 161 | .highlight .mf { 162 | color: #009999; } 163 | .highlight .mh { 164 | color: #009999; } 165 | .highlight .mi { 166 | color: #009999; } 167 | .highlight .mo { 168 | color: #009999; } 169 | .highlight .sb { 170 | color: #d14; } 171 | .highlight .sc { 172 | color: #d14; } 173 | .highlight .sd { 174 | color: #d14; } 175 | .highlight .s2 { 176 | color: #d14; } 177 | .highlight .se { 178 | color: #d14; } 179 | .highlight .sh { 180 | color: #d14; } 181 | .highlight .si { 182 | color: #d14; } 183 | .highlight .sx { 184 | color: #d14; } 185 | .highlight .sr { 186 | color: #009926; } 187 | .highlight .s1 { 188 | color: #d14; } 189 | .highlight .ss { 190 | color: #990073; } 191 | .highlight .bp { 192 | color: #999999; } 193 | .highlight .vc { 194 | color: #008080; } 195 | .highlight .vg { 196 | color: #008080; } 197 | .highlight .vi { 198 | color: #008080; } 199 | .highlight .il { 200 | color: #009999; } 201 | -------------------------------------------------------------------------------- /docs/docsets/StartupReasonReporter.docset/Contents/Resources/Documents/css/jazzy.css: -------------------------------------------------------------------------------- 1 | html, body, div, span, h1, h3, h4, p, a, code, em, img, ul, li, table, tbody, tr, td { 2 | background: transparent; 3 | border: 0; 4 | margin: 0; 5 | outline: 0; 6 | padding: 0; 7 | vertical-align: baseline; } 8 | 9 | body { 10 | background-color: #f2f2f2; 11 | font-family: Helvetica, freesans, Arial, sans-serif; 12 | font-size: 14px; 13 | -webkit-font-smoothing: subpixel-antialiased; 14 | word-wrap: break-word; } 15 | 16 | h1, h2, h3 { 17 | margin-top: 0.8em; 18 | margin-bottom: 0.3em; 19 | font-weight: 100; 20 | color: black; } 21 | 22 | h1 { 23 | font-size: 2.5em; } 24 | 25 | h2 { 26 | font-size: 2em; 27 | border-bottom: 1px solid #e2e2e2; } 28 | 29 | h4 { 30 | font-size: 13px; 31 | line-height: 1.5; 32 | margin-top: 21px; } 33 | 34 | h5 { 35 | font-size: 1.1em; } 36 | 37 | h6 { 38 | font-size: 1.1em; 39 | color: #777; } 40 | 41 | .section-name { 42 | color: gray; 43 | display: block; 44 | font-family: Helvetica; 45 | font-size: 22px; 46 | font-weight: 100; 47 | margin-bottom: 15px; } 48 | 49 | pre, code { 50 | font: 0.95em Menlo, monospace; 51 | color: #777; 52 | word-wrap: normal; } 53 | 54 | p code, li code { 55 | background-color: #eee; 56 | padding: 2px 4px; 57 | border-radius: 4px; } 58 | 59 | a { 60 | color: #0088cc; 61 | text-decoration: none; } 62 | 63 | ul { 64 | padding-left: 15px; } 65 | 66 | li { 67 | line-height: 1.8em; } 68 | 69 | img { 70 | max-width: 100%; } 71 | 72 | blockquote { 73 | margin-left: 0; 74 | padding: 0 10px; 75 | border-left: 4px solid #ccc; } 76 | 77 | .content-wrapper { 78 | margin: 0 auto; 79 | width: 980px; } 80 | 81 | header { 82 | font-size: 0.85em; 83 | line-height: 26px; 84 | background-color: #414141; 85 | position: fixed; 86 | width: 100%; 87 | z-index: 1; } 88 | header img { 89 | padding-right: 6px; 90 | vertical-align: -4px; 91 | height: 16px; } 92 | header a { 93 | color: #fff; } 94 | header p { 95 | float: left; 96 | color: #999; } 97 | header .header-right { 98 | float: right; 99 | margin-left: 16px; } 100 | 101 | #breadcrumbs { 102 | background-color: #f2f2f2; 103 | height: 27px; 104 | padding-top: 17px; 105 | position: fixed; 106 | width: 100%; 107 | z-index: 1; 108 | margin-top: 26px; } 109 | #breadcrumbs #carat { 110 | height: 10px; 111 | margin: 0 5px; } 112 | 113 | .sidebar { 114 | background-color: #f9f9f9; 115 | border: 1px solid #e2e2e2; 116 | overflow-y: auto; 117 | overflow-x: hidden; 118 | position: fixed; 119 | top: 70px; 120 | bottom: 0; 121 | width: 230px; 122 | word-wrap: normal; } 123 | 124 | .nav-groups { 125 | list-style-type: none; 126 | background: #fff; 127 | padding-left: 0; } 128 | 129 | .nav-group-name { 130 | border-bottom: 1px solid #e2e2e2; 131 | font-size: 1.1em; 132 | font-weight: 100; 133 | padding: 15px 0 15px 20px; } 134 | .nav-group-name > a { 135 | color: #333; } 136 | 137 | .nav-group-tasks { 138 | margin-top: 5px; } 139 | 140 | .nav-group-task { 141 | font-size: 0.9em; 142 | list-style-type: none; 143 | white-space: nowrap; } 144 | .nav-group-task a { 145 | color: #888; } 146 | 147 | .main-content { 148 | background-color: #fff; 149 | border: 1px solid #e2e2e2; 150 | margin-left: 246px; 151 | position: absolute; 152 | overflow: hidden; 153 | padding-bottom: 60px; 154 | top: 70px; 155 | width: 734px; } 156 | .main-content p, .main-content a, .main-content code, .main-content em, .main-content ul, .main-content table, .main-content blockquote { 157 | margin-bottom: 1em; } 158 | .main-content p { 159 | line-height: 1.8em; } 160 | .main-content section .section:first-child { 161 | margin-top: 0; 162 | padding-top: 0; } 163 | .main-content section .task-group-section .task-group:first-of-type { 164 | padding-top: 10px; } 165 | .main-content section .task-group-section .task-group:first-of-type .section-name { 166 | padding-top: 15px; } 167 | 168 | .section { 169 | padding: 0 25px; } 170 | 171 | .highlight { 172 | background-color: #eee; 173 | padding: 10px 12px; 174 | border: 1px solid #e2e2e2; 175 | border-radius: 4px; 176 | overflow-x: auto; } 177 | 178 | .declaration .highlight { 179 | overflow-x: initial; 180 | padding: 0 40px 40px 0; 181 | margin-bottom: -25px; 182 | background-color: transparent; 183 | border: none; } 184 | 185 | .section-name { 186 | margin: 0; 187 | margin-left: 18px; } 188 | 189 | .task-group-section { 190 | padding-left: 6px; 191 | border-top: 1px solid #e2e2e2; } 192 | 193 | .task-group { 194 | padding-top: 0px; } 195 | 196 | .task-name-container a[name]:before { 197 | content: ""; 198 | display: block; 199 | padding-top: 70px; 200 | margin: -70px 0 0; } 201 | 202 | .item { 203 | padding-top: 8px; 204 | width: 100%; 205 | list-style-type: none; } 206 | .item a[name]:before { 207 | content: ""; 208 | display: block; 209 | padding-top: 70px; 210 | margin: -70px 0 0; } 211 | .item code { 212 | background-color: transparent; 213 | padding: 0; } 214 | .item .token { 215 | padding-left: 3px; 216 | margin-left: 15px; 217 | font-size: 11.9px; } 218 | .item .declaration-note { 219 | font-size: .85em; 220 | color: gray; 221 | font-style: italic; } 222 | 223 | .pointer-container { 224 | border-bottom: 1px solid #e2e2e2; 225 | left: -23px; 226 | padding-bottom: 13px; 227 | position: relative; 228 | width: 110%; } 229 | 230 | .pointer { 231 | background: #f9f9f9; 232 | border-left: 1px solid #e2e2e2; 233 | border-top: 1px solid #e2e2e2; 234 | height: 12px; 235 | left: 21px; 236 | top: -7px; 237 | -webkit-transform: rotate(45deg); 238 | -moz-transform: rotate(45deg); 239 | -o-transform: rotate(45deg); 240 | transform: rotate(45deg); 241 | position: absolute; 242 | width: 12px; } 243 | 244 | .height-container { 245 | display: none; 246 | left: -25px; 247 | padding: 0 25px; 248 | position: relative; 249 | width: 100%; 250 | overflow: hidden; } 251 | .height-container .section { 252 | background: #f9f9f9; 253 | border-bottom: 1px solid #e2e2e2; 254 | left: -25px; 255 | position: relative; 256 | width: 100%; 257 | padding-top: 10px; 258 | padding-bottom: 5px; } 259 | 260 | .aside, .language { 261 | padding: 6px 12px; 262 | margin: 12px 0; 263 | border-left: 5px solid #dddddd; 264 | overflow-y: hidden; } 265 | .aside .aside-title, .language .aside-title { 266 | font-size: 9px; 267 | letter-spacing: 2px; 268 | text-transform: uppercase; 269 | padding-bottom: 0; 270 | margin: 0; 271 | color: #aaa; 272 | -webkit-user-select: none; } 273 | .aside p:last-child, .language p:last-child { 274 | margin-bottom: 0; } 275 | 276 | .language { 277 | border-left: 5px solid #cde9f4; } 278 | .language .aside-title { 279 | color: #4b8afb; } 280 | 281 | .aside-warning { 282 | border-left: 5px solid #ff6666; } 283 | .aside-warning .aside-title { 284 | color: #ff0000; } 285 | 286 | .graybox { 287 | border-collapse: collapse; 288 | width: 100%; } 289 | .graybox p { 290 | margin: 0; 291 | word-break: break-word; 292 | min-width: 50px; } 293 | .graybox td { 294 | border: 1px solid #e2e2e2; 295 | padding: 5px 25px 5px 10px; 296 | vertical-align: middle; } 297 | .graybox tr td:first-of-type { 298 | text-align: right; 299 | padding: 7px; 300 | vertical-align: top; 301 | word-break: normal; 302 | width: 40px; } 303 | 304 | .slightly-smaller { 305 | font-size: 0.9em; } 306 | 307 | #footer { 308 | position: absolute; 309 | bottom: 10px; 310 | margin-left: 25px; } 311 | #footer p { 312 | margin: 0; 313 | color: #aaa; 314 | font-size: 0.8em; } 315 | 316 | html.dash header, html.dash #breadcrumbs, html.dash .sidebar { 317 | display: none; } 318 | html.dash .main-content { 319 | width: 980px; 320 | margin-left: 0; 321 | border: none; 322 | width: 100%; 323 | top: 0; 324 | padding-bottom: 0; } 325 | html.dash .height-container { 326 | display: block; } 327 | html.dash .item .token { 328 | margin-left: 0; } 329 | html.dash .content-wrapper { 330 | width: auto; } 331 | html.dash #footer { 332 | position: static; } 333 | -------------------------------------------------------------------------------- /docs/docsets/StartupReasonReporter.docset/Contents/Resources/Documents/img/carat.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/uber/startup-reason-reporter/ad3e2d8c793a7b7a79118f0009a45cc12d74752c/docs/docsets/StartupReasonReporter.docset/Contents/Resources/Documents/img/carat.png -------------------------------------------------------------------------------- /docs/docsets/StartupReasonReporter.docset/Contents/Resources/Documents/img/dash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/uber/startup-reason-reporter/ad3e2d8c793a7b7a79118f0009a45cc12d74752c/docs/docsets/StartupReasonReporter.docset/Contents/Resources/Documents/img/dash.png -------------------------------------------------------------------------------- /docs/docsets/StartupReasonReporter.docset/Contents/Resources/Documents/img/gh.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/uber/startup-reason-reporter/ad3e2d8c793a7b7a79118f0009a45cc12d74752c/docs/docsets/StartupReasonReporter.docset/Contents/Resources/Documents/img/gh.png -------------------------------------------------------------------------------- /docs/docsets/StartupReasonReporter.docset/Contents/Resources/Documents/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | StartupReasonReporter Reference 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 |
16 |

StartupReasonReporter Docs (100% documented)

17 |

View on GitHub

18 |
19 |
20 |
21 | 26 |
27 |
28 | 91 |
92 |
93 |
94 | 95 |

Startup Reason Reporter Build Status

96 | 97 |

The Startup Reason Reporter provides developers the reason that an iOS application has launched, or equivalently, the reason that the application terminated on the prior launch.

98 |

Use

99 | 100 |

Usage is fairly straight-forward:

101 | 102 |

Swift:

103 |
// Determine whether the app crashed on a prior launch
104 | let crashedOnPriorLaunch = ...
105 | 
106 | // Initialize a storage mechanism implementing UBApplicationStartupReasonReporterPriorRunInfoProtocol
107 | let previousRunInfo: ApplicationStartupReasonReporterProtocol = ...
108 | 
109 | // Initialize the startup reason reporter
110 | let startupReasonReporter = ApplicationStartupReasonReporter(notificationCenter: NotificationCenter.default, 
111 | previousRunDidCrash: crashedOnPreviousLaunch, 
112 | previousRunInfo: previousRunInfo, 
113 | debugging: false)
114 | 
115 | // Profit
116 | let startupReason =  startupReasonReporter.startupReason
117 | 
118 | 119 |

Obj-C:

120 |
// Determine whether the app crashed on a prior launch
121 | BOOL crashedOnPriorLaunch = ...
122 | 
123 | // Initialize a storage mechanism implementing UBApplicationStartupReasonReporterPriorRunInfoProtocol
124 | id<UBApplicationStartupReasonReporterPriorRunInfoProtocol> runInfo = ...
125 | 
126 | // Initialize the startup reason reporter
127 | UBApplicationStartupReasonReporter *applicationStartupReasonReporter = [[UBApplicationStartupReasonReporter alloc] initWithNotificationCenter:[NSNotificationCenter defaultCenter]
128 |         previousRunDidCrash:self.crashReporter.crashDetected
129 |         previousRunInfo:runInfo
130 |         debugging:[UBBuildType isDebugBuild]];
131 | 
132 | // Profit
133 | UBStartupReason startupReason = startupReasonReporter.startupReason
134 | 
135 |

Introduction

136 | 137 |

The UBStartupReasonReporter is based on the general idea that applications may terminate for a fixed set of reasons on iOS.

138 | 139 |

Through process of elimination, the UBStartupReasonReporter can detect important events such as OOM crashes and app upgrades. The full list of possible startup reasons is described below.

140 | 141 |

Critically, the reported startup reason is only as accurate as the the data that is provided to it. For instance, some crash detection mechanisms may not encompass all forms of crashes, which may throw off the reported reason.

142 | 143 |

Our process for detecting various startup reasons is detailed by Ali Ansari and Grzegorz Pstrucha in this blog post: Reducing FOOMs in the iOS app

144 | 145 |

In order for detection to work, you must provide a class that implements prior run storage and conforms to UBApplicationStartupReasonReporterPriorRunInfoProtocol. We provide one such class, backed by NSUserDefaults, in UBApplicationStartupReasonReporterPriorRunInfo, though you may also wish to implement your own version that is backed by your preferred storage mechanism.

146 | 147 |

Possible startup reasons are as follows:

148 |
UBStartupReason const UBStartupReasonDebug = @"debug";
149 | UBStartupReason const UBStartupReasonFirstTime = @"first_time";
150 | UBStartupReason const UBStartupReasonCrash = @"crash";
151 | UBStartupReason const UBStartupReasonForceQuit = @"force_quit";
152 | UBStartupReason const UBStartupReasonAppUpgrade = @"app_upgrade";
153 | UBStartupReason const UBStartupReasonOSUpgrade = @"os_upgrade";
154 | UBStartupReason const UBStartupReasonBackgroundEviction = @"background_eviction";
155 | UBStartupReason const UBStartupReasonRestart = @"restart";
156 | UBStartupReason const UBStartupReasonOutOfMemory = @"out_of_memory";
157 | 
158 |

Installation

159 |

CocoaPods

160 | 161 |

To integrate the StartupReasonReporter into your project add the following to your Podfile:

162 |
pod 'StartupReasonReporter', '~> 0.1'
163 | 
164 | 165 |

To integrate only the UBApplicationStartupReasonReporterPriorRunInfoProtocol protocol, but not the implementation, add the following to your Podfile:

166 |
pod 'StartupReasonReporter/Core', '~> 0.1'
167 | 
168 |

Carthage

169 | 170 |

To integrate the StartupReasonReporter into your project using Carthage add the following to your Cartfile:

171 |
github "uber/StartupReasonReporter" ~> 0.1
172 | 
173 |

Contributions

174 | 175 |

We’d love for you to contribute to our open source projects. Before we can accept your contributions, we kindly ask you to sign our Uber Contributor License Agreement.

176 | 177 |
    178 |
  • If you find a bug, open an issue or submit a fix via a pull request.
  • 179 |
  • If you have a feature request, open an issue or submit an implementation via a pull request
  • 180 |
  • If you want to contribute, submit a pull request.
  • 181 |
182 |

License

183 |
Copyright (c) 2015 Uber Technologies, Inc.
184 | 
185 | Permission is hereby granted, free of charge, to any person obtaining a copy
186 | of this software and associated documentation files (the "Software"), to deal
187 | in the Software without restriction, including without limitation the rights
188 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
189 | copies of the Software, and to permit persons to whom the Software is
190 | furnished to do so, subject to the following conditions:
191 | 
192 | The above copyright notice and this permission notice shall be included in
193 | all copies or substantial portions of the Software.
194 | 
195 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
196 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
197 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
198 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
199 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
200 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
201 | THE SOFTWARE.
202 | 
203 | 204 |
205 |
206 | 210 |
211 |
212 | 213 | 214 | 215 | -------------------------------------------------------------------------------- /docs/docsets/StartupReasonReporter.docset/Contents/Resources/Documents/js/jazzy.js: -------------------------------------------------------------------------------- 1 | window.jazzy = {'docset': false} 2 | if (typeof window.dash != 'undefined') { 3 | document.documentElement.className += ' dash' 4 | window.jazzy.docset = true 5 | } 6 | if (navigator.userAgent.match(/xcode/i)) { 7 | document.documentElement.className += ' xcode' 8 | window.jazzy.docset = true 9 | } 10 | 11 | // On doc load, toggle the URL hash discussion if present 12 | $(document).ready(function() { 13 | if (!window.jazzy.docset) { 14 | var linkToHash = $('a[href="' + window.location.hash +'"]'); 15 | linkToHash.trigger("click"); 16 | } 17 | }); 18 | 19 | // On token click, toggle its discussion and animate token.marginLeft 20 | $(".token").click(function(event) { 21 | if (window.jazzy.docset) { 22 | return; 23 | } 24 | var link = $(this); 25 | var animationDuration = 300; 26 | var tokenOffset = "15px"; 27 | var original = link.css('marginLeft') == tokenOffset; 28 | link.animate({'margin-left':original ? "0px" : tokenOffset}, animationDuration); 29 | $content = link.parent().parent().next(); 30 | $content.slideToggle(animationDuration); 31 | 32 | // Keeps the document from jumping to the hash. 33 | var href = $(this).attr('href'); 34 | if (history.pushState) { 35 | history.pushState({}, '', href); 36 | } else { 37 | location.hash = href; 38 | } 39 | event.preventDefault(); 40 | }); 41 | 42 | // Dumb down quotes within code blocks that delimit strings instead of quotations 43 | // https://github.com/realm/jazzy/issues/714 44 | $("code q").replaceWith(function () { 45 | return ["\"", $(this).contents(), "\""]; 46 | }); 47 | -------------------------------------------------------------------------------- /docs/docsets/StartupReasonReporter.docset/Contents/Resources/Documents/search.json: -------------------------------------------------------------------------------- 1 | {"Type Definitions.html#/c:UBApplicationStartupReasonReporter.h@T@UBStartupReason":{"name":"UBStartupReason","abstract":"

A reason that the application launched.

"},"Protocols/UBApplicationStartupReasonReporterPriorRunInfoProtocol.html#/c:objc(pl)UBApplicationStartupReasonReporterPriorRunInfoProtocol(py)hasData":{"name":"hasData","abstract":"

Indicates whether data exists for the prior run. Generally, this will be false on the first run and true thereafter.

","parent_name":"UBApplicationStartupReasonReporterPriorRunInfoProtocol"},"Protocols/UBApplicationStartupReasonReporterPriorRunInfoProtocol.html#/c:objc(pl)UBApplicationStartupReasonReporterPriorRunInfoProtocol(py)previousAppVersion":{"name":"previousAppVersion","abstract":"

The app version of the prior app run.

","parent_name":"UBApplicationStartupReasonReporterPriorRunInfoProtocol"},"Protocols/UBApplicationStartupReasonReporterPriorRunInfoProtocol.html#/c:objc(pl)UBApplicationStartupReasonReporterPriorRunInfoProtocol(py)previousOSVersion":{"name":"previousOSVersion","abstract":"

The OS version of the prior app run.

","parent_name":"UBApplicationStartupReasonReporterPriorRunInfoProtocol"},"Protocols/UBApplicationStartupReasonReporterPriorRunInfoProtocol.html#/c:objc(pl)UBApplicationStartupReasonReporterPriorRunInfoProtocol(py)previousBootTime":{"name":"previousBootTime","abstract":"

The boot time of the prior app run.

","parent_name":"UBApplicationStartupReasonReporterPriorRunInfoProtocol"},"Protocols/UBApplicationStartupReasonReporterPriorRunInfoProtocol.html#/c:objc(pl)UBApplicationStartupReasonReporterPriorRunInfoProtocol(py)backgrounded":{"name":"backgrounded","abstract":"

Indicates whether the prior app run was backgrounded.

","parent_name":"UBApplicationStartupReasonReporterPriorRunInfoProtocol"},"Protocols/UBApplicationStartupReasonReporterPriorRunInfoProtocol.html#/c:objc(pl)UBApplicationStartupReasonReporterPriorRunInfoProtocol(py)didTerminate":{"name":"didTerminate","abstract":"

Indicates whether the prior app run was terminated.

","parent_name":"UBApplicationStartupReasonReporterPriorRunInfoProtocol"},"Protocols/UBApplicationStartupReasonReporterPriorRunInfoProtocol.html#/c:objc(pl)UBApplicationStartupReasonReporterPriorRunInfoProtocol(im)persist":{"name":"-persist","abstract":"

Persists the current prior run info to disk.

","parent_name":"UBApplicationStartupReasonReporterPriorRunInfoProtocol"},"Protocols/UBApplicationStartupReasonReporterPriorRunInfoProtocol.html":{"name":"UBApplicationStartupReasonReporterPriorRunInfoProtocol","abstract":"

Defines a storage interface for the UBApplicationStartupReasonReporter."},"Constants.html#/c:@UBStartupReasonDebug":{"name":"UBStartupReasonDebug","abstract":"

The application is being debugged.

"},"Constants.html#/c:@UBStartupReasonFirstTime":{"name":"UBStartupReasonFirstTime","abstract":"

The application was started for the first time.

"},"Constants.html#/c:@UBStartupReasonCrash":{"name":"UBStartupReasonCrash","abstract":"

The application started because it previously crashed.

"},"Constants.html#/c:@UBStartupReasonForceQuit":{"name":"UBStartupReasonForceQuit","abstract":"

The application started since it was force quit on the last run.

"},"Constants.html#/c:@UBStartupReasonAppUpgrade":{"name":"UBStartupReasonAppUpgrade","abstract":"

The application started because it was upgraded.

"},"Constants.html#/c:@UBStartupReasonOSUpgrade":{"name":"UBStartupReasonOSUpgrade","abstract":"

The application started because the OS was upgraded.

"},"Constants.html#/c:@UBStartupReasonBackgroundEviction":{"name":"UBStartupReasonBackgroundEviction","abstract":"

The application started because it was evicted from background on the last run.

"},"Constants.html#/c:@UBStartupReasonRestart":{"name":"UBStartupReasonRestart","abstract":"

The application started because the device was restarted after the last run.

"},"Constants.html#/c:@UBStartupReasonOutOfMemory":{"name":"UBStartupReasonOutOfMemory","abstract":"

The application started because it ran out of memory in the foreground.

"},"Classes/UBApplicationStartupReasonReporterPriorRunInfo.html#/c:objc(cs)UBApplicationStartupReasonReporterPriorRunInfo(im)initWithUserDefaults:":{"name":"-initWithUserDefaults:","abstract":"

Initializes a new UBApplicationStartupReasonReporterPriorRunInfo

","parent_name":"UBApplicationStartupReasonReporterPriorRunInfo"},"Classes/UBApplicationStartupReasonReporter.html#/c:objc(cs)UBApplicationStartupReasonReporter(py)startupReason":{"name":"startupReason","abstract":"

The reason the application started up.

","parent_name":"UBApplicationStartupReasonReporter"},"Classes/UBApplicationStartupReasonReporter.html#/c:objc(cs)UBApplicationStartupReasonReporter(cm)systemBootTime":{"name":"+systemBootTime","abstract":"

The time when the system was last booted.

","parent_name":"UBApplicationStartupReasonReporter"},"Classes/UBApplicationStartupReasonReporter.html#/c:objc(cs)UBApplicationStartupReasonReporter(im)init":{"name":"-init","abstract":"

Unavailable.

","parent_name":"UBApplicationStartupReasonReporter"},"Classes/UBApplicationStartupReasonReporter.html#/c:objc(cs)UBApplicationStartupReasonReporter(im)initWithNotificationCenter:previousRunDidCrash:previousRunInfo:debugging:":{"name":"-initWithNotificationCenter:previousRunDidCrash:previousRunInfo:debugging:","abstract":"

Initializes a new UBApplicationStartupReasonReporter.

","parent_name":"UBApplicationStartupReasonReporter"},"Classes/UBApplicationStartupReasonReporter.html":{"name":"UBApplicationStartupReasonReporter","abstract":"

The Startup Reason Reporter provides developers with the reason that an iOS application has launched, or equivalently, the reason that the application terminated on the prior launch.

"},"Classes/UBApplicationStartupReasonReporterPriorRunInfo.html":{"name":"UBApplicationStartupReasonReporterPriorRunInfo","abstract":"

An NSUserDefaults based implementation of UBApplicationStartupReasonReporterPriorRunInfoProtocol

"},"Classes.html":{"name":"Classes","abstract":"The following classes are available globally."},"Constants.html":{"name":"Constants","abstract":"The following constants are available globally."},"Protocols.html":{"name":"Protocols","abstract":"The following protocols are available globally."},"Type Definitions.html":{"name":"Type Definitions","abstract":"The following type definitions are available globally."}} -------------------------------------------------------------------------------- /docs/docsets/StartupReasonReporter.docset/Contents/Resources/Documents/undocumented.json: -------------------------------------------------------------------------------- 1 | { 2 | "warnings": [ 3 | 4 | ], 5 | "source_directory": "/Users/alexm/Desktop/startup-reason-reporter" 6 | } -------------------------------------------------------------------------------- /docs/docsets/StartupReasonReporter.docset/Contents/Resources/docSet.dsidx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/uber/startup-reason-reporter/ad3e2d8c793a7b7a79118f0009a45cc12d74752c/docs/docsets/StartupReasonReporter.docset/Contents/Resources/docSet.dsidx -------------------------------------------------------------------------------- /docs/docsets/StartupReasonReporter.tgz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/uber/startup-reason-reporter/ad3e2d8c793a7b7a79118f0009a45cc12d74752c/docs/docsets/StartupReasonReporter.tgz -------------------------------------------------------------------------------- /docs/img/carat.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/uber/startup-reason-reporter/ad3e2d8c793a7b7a79118f0009a45cc12d74752c/docs/img/carat.png -------------------------------------------------------------------------------- /docs/img/dash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/uber/startup-reason-reporter/ad3e2d8c793a7b7a79118f0009a45cc12d74752c/docs/img/dash.png -------------------------------------------------------------------------------- /docs/img/gh.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/uber/startup-reason-reporter/ad3e2d8c793a7b7a79118f0009a45cc12d74752c/docs/img/gh.png -------------------------------------------------------------------------------- /docs/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | StartupReasonReporter Reference 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 |
16 |

StartupReasonReporter Docs (100% documented)

17 |

View on GitHub

18 |
19 |
20 |
21 | 26 |
27 |
28 | 91 |
92 |
93 |
94 | 95 |

Startup Reason Reporter Build Status

96 | 97 |

The Startup Reason Reporter provides developers the reason that an iOS application has launched, or equivalently, the reason that the application terminated on the prior launch.

98 |

Use

99 | 100 |

Usage is fairly straight-forward:

101 | 102 |

Swift:

103 |
// Determine whether the app crashed on a prior launch
104 | let crashedOnPriorLaunch = ...
105 | 
106 | // Initialize a storage mechanism implementing UBApplicationStartupReasonReporterPriorRunInfoProtocol
107 | let previousRunInfo: ApplicationStartupReasonReporterProtocol = ...
108 | 
109 | // Initialize the startup reason reporter
110 | let startupReasonReporter = ApplicationStartupReasonReporter(notificationCenter: NotificationCenter.default, 
111 | previousRunDidCrash: crashedOnPreviousLaunch, 
112 | previousRunInfo: previousRunInfo, 
113 | debugging: false)
114 | 
115 | // Profit
116 | let startupReason =  startupReasonReporter.startupReason
117 | 
118 | 119 |

Obj-C:

120 |
// Determine whether the app crashed on a prior launch
121 | BOOL crashedOnPriorLaunch = ...
122 | 
123 | // Initialize a storage mechanism implementing UBApplicationStartupReasonReporterPriorRunInfoProtocol
124 | id<UBApplicationStartupReasonReporterPriorRunInfoProtocol> runInfo = ...
125 | 
126 | // Initialize the startup reason reporter
127 | UBApplicationStartupReasonReporter *applicationStartupReasonReporter = [[UBApplicationStartupReasonReporter alloc] initWithNotificationCenter:[NSNotificationCenter defaultCenter]
128 |         previousRunDidCrash:self.crashReporter.crashDetected
129 |         previousRunInfo:runInfo
130 |         debugging:[UBBuildType isDebugBuild]];
131 | 
132 | // Profit
133 | UBStartupReason startupReason = startupReasonReporter.startupReason
134 | 
135 |

Introduction

136 | 137 |

The UBStartupReasonReporter is based on the general idea that applications may terminate for a fixed set of reasons on iOS.

138 | 139 |

Through process of elimination, the UBStartupReasonReporter can detect important events such as OOM crashes and app upgrades. The full list of possible startup reasons is described below.

140 | 141 |

Critically, the reported startup reason is only as accurate as the the data that is provided to it. For instance, some crash detection mechanisms may not encompass all forms of crashes, which may throw off the reported reason.

142 | 143 |

Our process for detecting various startup reasons is detailed by Ali Ansari and Grzegorz Pstrucha in this blog post: Reducing FOOMs in the iOS app

144 | 145 |

In order for detection to work, you must provide a class that implements prior run storage and conforms to UBApplicationStartupReasonReporterPriorRunInfoProtocol. We provide one such class, backed by NSUserDefaults, in UBApplicationStartupReasonReporterPriorRunInfo, though you may also wish to implement your own version that is backed by your preferred storage mechanism.

146 | 147 |

Possible startup reasons are as follows:

148 |
UBStartupReason const UBStartupReasonDebug = @"debug";
149 | UBStartupReason const UBStartupReasonFirstTime = @"first_time";
150 | UBStartupReason const UBStartupReasonCrash = @"crash";
151 | UBStartupReason const UBStartupReasonForceQuit = @"force_quit";
152 | UBStartupReason const UBStartupReasonAppUpgrade = @"app_upgrade";
153 | UBStartupReason const UBStartupReasonOSUpgrade = @"os_upgrade";
154 | UBStartupReason const UBStartupReasonBackgroundEviction = @"background_eviction";
155 | UBStartupReason const UBStartupReasonRestart = @"restart";
156 | UBStartupReason const UBStartupReasonOutOfMemory = @"out_of_memory";
157 | 
158 |

Installation

159 |

CocoaPods

160 | 161 |

To integrate the StartupReasonReporter into your project add the following to your Podfile:

162 |
pod 'StartupReasonReporter', '~> 0.1'
163 | 
164 | 165 |

To integrate only the UBApplicationStartupReasonReporterPriorRunInfoProtocol protocol, but not the implementation, add the following to your Podfile:

166 |
pod 'StartupReasonReporter/Core', '~> 0.1'
167 | 
168 |

Carthage

169 | 170 |

To integrate the StartupReasonReporter into your project using Carthage add the following to your Cartfile:

171 |
github "uber/StartupReasonReporter" ~> 0.1
172 | 
173 |

Contributions

174 | 175 |

We’d love for you to contribute to our open source projects. Before we can accept your contributions, we kindly ask you to sign our Uber Contributor License Agreement.

176 | 177 |
    178 |
  • If you find a bug, open an issue or submit a fix via a pull request.
  • 179 |
  • If you have a feature request, open an issue or submit an implementation via a pull request
  • 180 |
  • If you want to contribute, submit a pull request.
  • 181 |
182 |

License

183 |
Copyright (c) 2015 Uber Technologies, Inc.
184 | 
185 | Permission is hereby granted, free of charge, to any person obtaining a copy
186 | of this software and associated documentation files (the "Software"), to deal
187 | in the Software without restriction, including without limitation the rights
188 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
189 | copies of the Software, and to permit persons to whom the Software is
190 | furnished to do so, subject to the following conditions:
191 | 
192 | The above copyright notice and this permission notice shall be included in
193 | all copies or substantial portions of the Software.
194 | 
195 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
196 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
197 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
198 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
199 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
200 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
201 | THE SOFTWARE.
202 | 
203 | 204 |
205 |
206 | 210 |
211 |
212 | 213 | 214 | 215 | -------------------------------------------------------------------------------- /docs/js/jazzy.js: -------------------------------------------------------------------------------- 1 | window.jazzy = {'docset': false} 2 | if (typeof window.dash != 'undefined') { 3 | document.documentElement.className += ' dash' 4 | window.jazzy.docset = true 5 | } 6 | if (navigator.userAgent.match(/xcode/i)) { 7 | document.documentElement.className += ' xcode' 8 | window.jazzy.docset = true 9 | } 10 | 11 | // On doc load, toggle the URL hash discussion if present 12 | $(document).ready(function() { 13 | if (!window.jazzy.docset) { 14 | var linkToHash = $('a[href="' + window.location.hash +'"]'); 15 | linkToHash.trigger("click"); 16 | } 17 | }); 18 | 19 | // On token click, toggle its discussion and animate token.marginLeft 20 | $(".token").click(function(event) { 21 | if (window.jazzy.docset) { 22 | return; 23 | } 24 | var link = $(this); 25 | var animationDuration = 300; 26 | var tokenOffset = "15px"; 27 | var original = link.css('marginLeft') == tokenOffset; 28 | link.animate({'margin-left':original ? "0px" : tokenOffset}, animationDuration); 29 | $content = link.parent().parent().next(); 30 | $content.slideToggle(animationDuration); 31 | 32 | // Keeps the document from jumping to the hash. 33 | var href = $(this).attr('href'); 34 | if (history.pushState) { 35 | history.pushState({}, '', href); 36 | } else { 37 | location.hash = href; 38 | } 39 | event.preventDefault(); 40 | }); 41 | 42 | // Dumb down quotes within code blocks that delimit strings instead of quotations 43 | // https://github.com/realm/jazzy/issues/714 44 | $("code q").replaceWith(function () { 45 | return ["\"", $(this).contents(), "\""]; 46 | }); 47 | -------------------------------------------------------------------------------- /docs/search.json: -------------------------------------------------------------------------------- 1 | {"Type Definitions.html#/c:UBApplicationStartupReasonReporter.h@T@UBStartupReason":{"name":"UBStartupReason","abstract":"

A reason that the application launched.

"},"Protocols/UBApplicationStartupReasonReporterPriorRunInfoProtocol.html#/c:objc(pl)UBApplicationStartupReasonReporterPriorRunInfoProtocol(py)hasData":{"name":"hasData","abstract":"

Indicates whether data exists for the prior run. Generally, this will be false on the first run and true thereafter.

","parent_name":"UBApplicationStartupReasonReporterPriorRunInfoProtocol"},"Protocols/UBApplicationStartupReasonReporterPriorRunInfoProtocol.html#/c:objc(pl)UBApplicationStartupReasonReporterPriorRunInfoProtocol(py)previousAppVersion":{"name":"previousAppVersion","abstract":"

The app version of the prior app run.

","parent_name":"UBApplicationStartupReasonReporterPriorRunInfoProtocol"},"Protocols/UBApplicationStartupReasonReporterPriorRunInfoProtocol.html#/c:objc(pl)UBApplicationStartupReasonReporterPriorRunInfoProtocol(py)previousOSVersion":{"name":"previousOSVersion","abstract":"

The OS version of the prior app run.

","parent_name":"UBApplicationStartupReasonReporterPriorRunInfoProtocol"},"Protocols/UBApplicationStartupReasonReporterPriorRunInfoProtocol.html#/c:objc(pl)UBApplicationStartupReasonReporterPriorRunInfoProtocol(py)previousBootTime":{"name":"previousBootTime","abstract":"

The boot time of the prior app run.

","parent_name":"UBApplicationStartupReasonReporterPriorRunInfoProtocol"},"Protocols/UBApplicationStartupReasonReporterPriorRunInfoProtocol.html#/c:objc(pl)UBApplicationStartupReasonReporterPriorRunInfoProtocol(py)backgrounded":{"name":"backgrounded","abstract":"

Indicates whether the prior app run was backgrounded.

","parent_name":"UBApplicationStartupReasonReporterPriorRunInfoProtocol"},"Protocols/UBApplicationStartupReasonReporterPriorRunInfoProtocol.html#/c:objc(pl)UBApplicationStartupReasonReporterPriorRunInfoProtocol(py)didTerminate":{"name":"didTerminate","abstract":"

Indicates whether the prior app run was terminated.

","parent_name":"UBApplicationStartupReasonReporterPriorRunInfoProtocol"},"Protocols/UBApplicationStartupReasonReporterPriorRunInfoProtocol.html#/c:objc(pl)UBApplicationStartupReasonReporterPriorRunInfoProtocol(im)persist":{"name":"-persist","abstract":"

Persists the current prior run info to disk.

","parent_name":"UBApplicationStartupReasonReporterPriorRunInfoProtocol"},"Protocols/UBApplicationStartupReasonReporterPriorRunInfoProtocol.html":{"name":"UBApplicationStartupReasonReporterPriorRunInfoProtocol","abstract":"

Defines a storage interface for the UBApplicationStartupReasonReporter."},"Constants.html#/c:@UBStartupReasonDebug":{"name":"UBStartupReasonDebug","abstract":"

The application is being debugged.

"},"Constants.html#/c:@UBStartupReasonFirstTime":{"name":"UBStartupReasonFirstTime","abstract":"

The application was started for the first time.

"},"Constants.html#/c:@UBStartupReasonCrash":{"name":"UBStartupReasonCrash","abstract":"

The application started because it previously crashed.

"},"Constants.html#/c:@UBStartupReasonForceQuit":{"name":"UBStartupReasonForceQuit","abstract":"

The application started since it was force quit on the last run.

"},"Constants.html#/c:@UBStartupReasonAppUpgrade":{"name":"UBStartupReasonAppUpgrade","abstract":"

The application started because it was upgraded.

"},"Constants.html#/c:@UBStartupReasonOSUpgrade":{"name":"UBStartupReasonOSUpgrade","abstract":"

The application started because the OS was upgraded.

"},"Constants.html#/c:@UBStartupReasonBackgroundEviction":{"name":"UBStartupReasonBackgroundEviction","abstract":"

The application started because it was evicted from background on the last run.

"},"Constants.html#/c:@UBStartupReasonRestart":{"name":"UBStartupReasonRestart","abstract":"

The application started because the device was restarted after the last run.

"},"Constants.html#/c:@UBStartupReasonOutOfMemory":{"name":"UBStartupReasonOutOfMemory","abstract":"

The application started because it ran out of memory in the foreground.

"},"Classes/UBApplicationStartupReasonReporterPriorRunInfo.html#/c:objc(cs)UBApplicationStartupReasonReporterPriorRunInfo(im)initWithUserDefaults:":{"name":"-initWithUserDefaults:","abstract":"

Initializes a new UBApplicationStartupReasonReporterPriorRunInfo

","parent_name":"UBApplicationStartupReasonReporterPriorRunInfo"},"Classes/UBApplicationStartupReasonReporter.html#/c:objc(cs)UBApplicationStartupReasonReporter(py)startupReason":{"name":"startupReason","abstract":"

The reason the application started up.

","parent_name":"UBApplicationStartupReasonReporter"},"Classes/UBApplicationStartupReasonReporter.html#/c:objc(cs)UBApplicationStartupReasonReporter(cm)systemBootTime":{"name":"+systemBootTime","abstract":"

The time when the system was last booted.

","parent_name":"UBApplicationStartupReasonReporter"},"Classes/UBApplicationStartupReasonReporter.html#/c:objc(cs)UBApplicationStartupReasonReporter(im)init":{"name":"-init","abstract":"

Unavailable.

","parent_name":"UBApplicationStartupReasonReporter"},"Classes/UBApplicationStartupReasonReporter.html#/c:objc(cs)UBApplicationStartupReasonReporter(im)initWithNotificationCenter:previousRunDidCrash:previousRunInfo:debugging:":{"name":"-initWithNotificationCenter:previousRunDidCrash:previousRunInfo:debugging:","abstract":"

Initializes a new UBApplicationStartupReasonReporter.

","parent_name":"UBApplicationStartupReasonReporter"},"Classes/UBApplicationStartupReasonReporter.html":{"name":"UBApplicationStartupReasonReporter","abstract":"

The Startup Reason Reporter provides developers with the reason that an iOS application has launched, or equivalently, the reason that the application terminated on the prior launch.

"},"Classes/UBApplicationStartupReasonReporterPriorRunInfo.html":{"name":"UBApplicationStartupReasonReporterPriorRunInfo","abstract":"

An NSUserDefaults based implementation of UBApplicationStartupReasonReporterPriorRunInfoProtocol

"},"Classes.html":{"name":"Classes","abstract":"The following classes are available globally."},"Constants.html":{"name":"Constants","abstract":"The following constants are available globally."},"Protocols.html":{"name":"Protocols","abstract":"The following protocols are available globally."},"Type Definitions.html":{"name":"Type Definitions","abstract":"The following type definitions are available globally."}} -------------------------------------------------------------------------------- /docs/undocumented.json: -------------------------------------------------------------------------------- 1 | { 2 | "warnings": [ 3 | 4 | ], 5 | "source_directory": "/Users/alexm/Desktop/startup-reason-reporter" 6 | } -------------------------------------------------------------------------------- /generate_docs.sh: -------------------------------------------------------------------------------- 1 | jazzy \ 2 | --objc \ 3 | --author "Uber Engineering" \ 4 | --author_url http://eng.uber.com \ 5 | --github_url https://github.com/uber/startup-reason-reporter \ 6 | --module-version 1.0.0 \ 7 | --umbrella-header StartupReasonReporter/StartupReasonReporter.h \ 8 | --framework-root . \ 9 | --module StartupReasonReporter --------------------------------------------------------------------------------