{"id":13719316,"url":"https://github.com/pixeldock/RxAppState","last_synced_at":"2025-05-07T11:31:28.298Z","repository":{"id":44721834,"uuid":"53272428","full_name":"pixeldock/RxAppState","owner":"pixeldock","description":"RxSwift extensions for UIApplicationDelegate methods to observe changes in your app's state","archived":false,"fork":false,"pushed_at":"2024-05-24T07:15:30.000Z","size":2015,"stargazers_count":389,"open_issues_count":0,"forks_count":45,"subscribers_count":8,"default_branch":"master","last_synced_at":"2025-04-28T19:49:26.705Z","etag":null,"topics":["carthage","cocoapods","rx-cocoa","rxswift","rxswift-extensions","swift","uiapplicationdelegate"],"latest_commit_sha":null,"homepage":"","language":"Swift","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/pixeldock.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2016-03-06T19:38:30.000Z","updated_at":"2025-04-20T08:01:21.000Z","dependencies_parsed_at":"2023-12-28T07:41:58.728Z","dependency_job_id":"393ddc79-cc89-4bd0-adc8-08b6d2862926","html_url":"https://github.com/pixeldock/RxAppState","commit_stats":{"total_commits":197,"total_committers":17,"mean_commits":"11.588235294117647","dds":"0.13197969543147203","last_synced_commit":"1c3f32433b4ffa431671b21e46b98af0d875081e"},"previous_names":[],"tags_count":28,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pixeldock%2FRxAppState","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pixeldock%2FRxAppState/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pixeldock%2FRxAppState/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pixeldock%2FRxAppState/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/pixeldock","download_url":"https://codeload.github.com/pixeldock/RxAppState/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":252868843,"owners_count":21816924,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["carthage","cocoapods","rx-cocoa","rxswift","rxswift-extensions","swift","uiapplicationdelegate"],"created_at":"2024-08-03T01:00:46.300Z","updated_at":"2025-05-07T11:31:27.765Z","avatar_url":"https://github.com/pixeldock.png","language":"Swift","funding_links":[],"categories":["Libraries"],"sub_categories":[],"readme":"# RxAppState\n\n[![CI Status](https://img.shields.io/travis/com/pixeldock/RxAppState.svg?style=flat)](https://travis-ci.com/pixeldock/RxAppState)\n[![Platform](https://img.shields.io/cocoapods/p/RxAppState.svg?style=flat)](http://cocoapods.org/pods/RxAppState)\n[![Version](https://img.shields.io/cocoapods/v/RxAppState.svg?style=flat)](http://cocoapods.org/pods/RxAppState)\n[![Carthage compatible](https://img.shields.io/badge/Carthage-compatible-4BC51D.svg?style=flat)](https://github.com/Carthage/Carthage)\n[![SPM compatible](https://img.shields.io/badge/SPM-compatible-E05C43.svg?style=flat)](https://swift.org/package-manager/)\n[![Xcode](https://img.shields.io/badge/xcode-12-5995EE.svg?style=flat)](https://developer.apple.com)\n[![Swift](https://img.shields.io/badge/Swift-5-orange.svg?style=flat)](https://swift.org/)\n[![License](https://img.shields.io/cocoapods/l/RxAppState.svg?style=flat)](http://cocoapods.org/pods/RxAppState)\n[![Twitter](https://img.shields.io/badge/Twitter-@pixeldock-5E9FE5.svg?logo=twitter)](http://twitter.com/pixeldock)\n[![Blog](https://img.shields.io/badge/Blog-pixeldock-FF0066.svg?style=flat)](http://pixeldock.com/blog)\n\nA collection of handy RxSwift Observables that let you observe all the changes in your Application's state and your UIViewController view-related notifications.\n\n## About\n### Application states\nIn almost every app there is some code that you want to run each time a user opens the app. For example you want to refresh some data or track that the user opened your app.\n\n**UIApplicationDelegate** offers two methods that you could use to run the code when the user opens the app: _applicationWillEnterForeground_ and _applicationDidBecomeActive_. But either of these methods is not ideal for this case:\n\n_applicationWillEnterForeground_ is not called the first time your app is launched. It is only called when the app was in the background and then enters the foreground. At first launch the app is not in the background state so this methods does not get called.\n\n_applicationDidBecomeActive_ does get called when the app is launched for the first time but is also called when the app becomes active after being in inactive state. That happens everytime the user opens Control Center, Notification Center, receives a phone call or a system prompt is shown (e.g. to ask the user for permission to send remote notifications). So if you put your code in _applicationDidBecomeActive_ it will not only get called when the user opens the app but also in all those cases mentioned above.\n\nSo to really run your code only when your user opens the app you need to keep track of the app's state. You would probably implement something like this:\n\n```swift\nclass AppDelegate: UIResponder, UIApplicationDelegate {\n    var window: UIWindow?\n    var didEnterBackground = true\n    ...\n    func applicationDidEnterBackground(_ application: UIApplication) {\n        didEnterBackground = true\n    }\n    func applicationDidBecomeActive(_ application: UIApplication) {\n        if didEnterBackground {\n            // run your code\n            didEnterBackground = false\n        }\n    }\n    ...\n}\n```\nThis is not a big problem, but it is not a very elegant approach. And you have to set the inital value of _didEnterBackground_ to _true_ to run your code after the first launch (see above), even if the app never has been to the background. Call me picky, but I don't like that.\n\n**RxAppState to the rescue!**  \nWith RxAppState you can simply do the following:\n\n```swift\nUIApplication.shared.rx.didOpenApp\n    .subscribe(onNext: { _ in\n        // run your code\n    })\n    .disposed(by: disposeBag)\n```\nThis runs your code whenever the user opens the app. It includes the first launch of the app and ignores the cases when the app enters active state without having been in background state before (like when the user just opened Control Center or received a phone call)\n\n**And there is more!**  \nYou want to show your user a tutorial when he first launches the app? And you only want to show it after the first launch and never again? No problem:\n\n```swift\nUIApplication.shared.rx.firstLaunchOnly\n    .subscribe(onNext: { _ in\n        // run your code\n    })\n    .disposed(by: disposeBag)\n```\nYou want to show your user what features are new when he opens the app for the first time after an update?\n\n```swift\nUIApplication.shared.rx.firstLaunchOfNewVersionOnly\n    .subscribe(onNext: { version in\n        let previousAppVersion = version.previous\n        let currentAppVersion = version.current\n        // show what has changed between\n        // the previous and the current version\n    })\n    .disposed(by: disposeBag)\n```\n\nYou want check the previous and the current app version each time the user opens the app?\n\n```swift\nUIApplication.shared.rx.appVersion\n    .subscribe(onNext: { version in\n        let previousAppVersion = version.previous\n        let currentAppVersion = version.current\n        // run your code\n    })\n    .disposed(by: disposeBag)\n```\n\nYou want to keep track of how many times the user has opened your app? Simply do this:\n\n```swift\nUIApplication.shared.rx.didOpenAppCount\n    .subscribe(onNext: { count in\n        print(\"app opened \\(count) times\")\n    })\n    .disposed(by: disposeBag)\n```\n\n**The cherry on top:**   \nThis code does not have to live in your AppDelegate. You could put it anywhere you like in your app! So don't clutter your AppDelegate with this code, put it somewhere else!\n\n### ViewController view-related notifications\n\nYou can also use Observables to subscribe to your view controllers' view-related notifications:\n\nDo do something when your view controller's `viewDidAppear:` method is called you can do this in your view controller class:\n\n```swift\nrx.viewDidAppear\n    .subscribe(onNext: { animated in\n       // do something\n    })\n    .disposed(by: disposeBag)\n```\n\nIf you want to do something only when the view appeared for the first time you can easily do it like this:\n\n```swift\nrx.viewDidAppear\n    .take(1)\n    .subscribe(onNext: { animated in\n       // do something\n    })\n    .disposed(by: disposeBag)\n```\n\nYou can also directly bind you view controller's view state to another object:\n\n```swift\nrx.viewWillDisappear\n    .bind(to: viewModel.saveChanges)\n    .disposed(by: disposeBag)\n```\n\n\n## Example\nThere is a simple example project to demonstrate how to use RxAppDelegate.\n\n## Requirements\niOS 13   \nSwift 5.2\nXcode 15 \nIf you are still on Xcode 14 you can try to use the branch `/fix/xcode14-viewIsAppearing' (at own risk)\n\n\nIf you are using Swift 4.0 please use RxAppState version 1.1.1  \nIf you are using Swift 4.1 please use RxAppState version 1.1.2  \nIf you are using Swift 4.2 please use RxAppState version 1.4.1\n\n\n## Dependencies\nRxSwift 6.2 or greater\nRxCocoa 6.2 or greater\n\n## Integration\n### CocoaPods\n`RxAppState` is available through [CocoaPods](http://cocoapods.org). To install\nit, simply add the following line to your `Podfile`:\n\n```ruby\npod \"RxAppState\"\n```\n\nIf Xcode complains about Swift versions add this to the end of your Podfile:\n\n```ruby\npost_install do |installer|\n    installer.pods_project.targets.each do |target|\n        target.build_configurations.each do |config|\n            config.build_settings['SWIFT_VERSION'] = '5.0'\n        end\n    end\nend\n```\n\n### Carthage\n\nYou can use [Carthage](https://github.com/Carthage/Carthage) to install `RxAppState` by adding it to your `Cartfile`:\n\n```\ngithub \"pixeldock/RxAppState\"\n```\n\n### Swift Package Manager\n\nYou can use Swift Package Manager to install `RxAppState`:\n\nhttps://swift.org/package-manager/\n\n## Author\n\nJörn Schoppe,  \njoern@pixeldock.com   \n\n[![Twitter](https://img.shields.io/badge/Twitter-@pixeldock-blue.svg?style=flat)](http://twitter.com/pixeldock)\n[![Blog](https://img.shields.io/badge/Blog-pixeldock-FF0066.svg?style=flat)](http://pixeldock.com/blog)\n\n\n## License\n\nRxAppState is available under the MIT license. See the LICENSE file for more info.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpixeldock%2FRxAppState","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fpixeldock%2FRxAppState","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpixeldock%2FRxAppState/lists"}